|
22039
|
962
|
32
|
2026-05-12T06:46:12.929097+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-12/1778 /Users/lukas/.screenpipe/data/data/2026-05-12/1778568372929_m1.jpg...
|
CleanShot X
|
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
0:19
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"0:19","depth":1,"bounds":{"left":0.74756944,"top":0.9494445,"width":0.023611112,"height":0.015555556},"on_screen":true,"role_description":"text"}]...
|
-8105290342498011052
|
-8105290342498011052
|
visual_change
|
hybrid
|
NULL
|
0:19
FirefoxFileEditViewHistoryBookmarksProfilesTo 0:19
FirefoxFileEditViewHistoryBookmarksProfilesToolsWindowHelploblmeet.google.com/mie-gawc-dsi?authuser=lukas.kovalik%40jiminny.comNikolay Yankov (Presenting, annotating)ChromeFileViewHistoryTabWindowHelp19 SeAthttps://jiminny.atlassian.net/jira/software/c/projects/JY/boards/37*) SSHnateoakelorePlatform TeamQ Search boardEpic vType vQuick filters vREADY FOR DEVINDEV 3CODE REVIEW 2BLOCKEDmeet.google.comNkolsy Yankov (You, presenting, annotating)At*Jin* CHCMI3 мсO. Ask GoogleDatadogClaudeCircleCilComplete sprintQA 2PO ACCEPTANCEDaily - Platform - now100% <478•Tue 12 May 9:46:12•••8• Tue 12 May 9:46a(s|+CJ All BookmarksGroup: QueriesDEPLOY 9Nikolay NikolovStefka StoyanovaSYou are presentingTo avoid an infinity mirror, don't share your entire screen or browser window.Share just a tab or a different window instead.Show my screen anywayStop presenting2 othersNikolay NikolovLukas Kovaliktka StoyanovaNikolay YankovStellyan GeorgistAneliya AngelovaNikolayLukas Kovalik0:199:46 AM | Daily - PlatformLộ3...
|
22038
|
NULL
|
NULL
|
NULL
|
|
21511
|
NULL
|
0
|
2026-05-11T18:01:18.497666+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778522478497_m2.jpg...
|
Firefox
|
SQLite Web: db.sqlite — Personal
|
True
|
sqlite.screenpipe.lakylak.xyz/audio_transcriptions sqlite.screenpipe.lakylak.xyz/audio_transcriptions/content/...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
New Tab
New Tab
Screenpipe — Archive
Screenpipe — New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
All docs · AFFiNE
All docs · AFFiNE
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
sqlite-web 0.7.2
sqlite-web 0.7.2
db.sqlite
db.sqlite
audio_transcriptions
287 rows, showing page 1
Query
Query
table name...
_sqlx_migrations
_sqlx_migrations
audio_chunks
audio_chunks
audio_tags
audio_tags
audio_transcriptions
audio_transcriptions
audio_transcriptions_fts (v)
audio_transcriptions_fts
(v)
audio_transcriptions_...
audio_transcriptions_...
audio_transcriptions_...
audio_transcriptions_...
audio_transcriptions_...
audio_transcriptions_...
elements
elements
elements_fts (v)
elements_fts
(v)
elements_fts_config
elements_fts_config
elements_fts_data
elements_fts_data
elements_fts_idx
elements_fts_idx
frames
frames
frames_fts (v)
frames_fts
(v)
frames_fts_config
frames_fts_config
frames_fts_data
frames_fts_data
frames_fts_idx
frames_fts_idx
meetings
meetings
memories
memories
memories_fts (v)
memories_fts
(v)
memories_fts_config
memories_fts_config
memories_fts_data
memories_fts_data
memories_fts_idx
memories_fts_idx
ocr_text
ocr_text
pipe_executions
pipe_executions
pipe_scheduler_state
pipe_scheduler_state
secrets
secrets
speaker_embeddings
speaker_embeddings
speakers
speakers
sqlite_sequence
sqlite_sequence
sqlite_stat1
sqlite_stat1
sqlite_stat4
sqlite_stat4
tags
tags
ui_events
ui_events
ui_events_fts (v)
ui_events_fts
(v)
ui_events_fts_config
ui_events_fts_config
ui_events_fts_data
ui_events_fts_data
ui_events_fts_idx
ui_events_fts_idx
video_chunks
video_chunks
vision_tags
vision_tags
Toggle helper tables
Toggle helper tables
Structure
Structure
Content
Content
Query
Query
Export
Export
id
id
audio_chunk_id
audio_chunk_id
offset_index
offset_index
timestamp
timestamp
transcription
transcription
device
device
is_input_device
is_input_device
speaker_id
speaker_id
transcription_engine
transcription_engine
start_time
start_time
end_time
end_time
text_length
text_length
sync_id
sync_id
synced_at
synced_at
redacted_at
redacted_at
1
16
0
2026-05-10T11:10:32+00:00
We remember, we remember, start.
soundcore AeroClip
True
1
WhisperTiny
21.9150625
24.8513125
33
NULL
NULL
NULL
2
18
0
2026-05-10T11:11:05+00:00
We'll
soundcore AeroClip
True
1
WhisperTiny
12.7519375
22.0669375
5
NULL
NULL
NULL
3
21
0
2026-05-10T11:11:35+00:00
a good job. I don't know how many people are t
...
...
soundcore AeroClip
True
1
WhisperTiny
0.3319375
29.8631875
131
NULL
NULL
NULL
4
23
0
2026-05-10T11:42:53+00:00
What is the general approach towards transcribing
...
...
soundcore AeroClip
True
1
WhisperTiny
19.9238125
24.5475625
51
NULL
NULL
NULL
5
23
0
2026-05-10T11:42:53+00:00
delay?
soundcore AeroClip
True
1
WhisperTiny
25.6444375
26.4713125
6
NULL
NULL
NULL
6
25
0
2026-05-10T11:43:25+00:00
What is the play when transcribe is to spread poi
...
...
soundcore AeroClip
True
1
WhisperTiny
2.7450625
11.2669375
119
NULL
NULL
NULL
7
30
0
2026-05-10T11:44:25+00:00
Thank you.
soundcore AeroClip
True
1
WhisperTiny
19.7044375
29.8631875
11
NULL
NULL
NULL
8
31
0
2026-05-10T11:44:45+00:00
And
System Audio
False
1
WhisperTiny
11.9925625
22.7588125
3
NULL
NULL
NULL
9
31
0
2026-05-10T11:44:45+00:00
going to be going up to you.
System Audio
False
1
WhisperTiny
25.2731875
27.1125625
28
NULL
NULL
NULL
10
32
0
2026-05-10T11:44:55+00:00
I'll be back.
soundcore AeroClip
True
2
WhisperTiny
0.0450625
1.6988125
14
NULL
NULL
NULL
11
32
0
2026-05-10T11:44:55+00:00...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.5,"top":0.0518755,"width":0.06881649,"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.51329786,"top":0.06304868,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.5,"top":0.08459697,"width":0.06881649,"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.51329786,"top":0.09577015,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"All docs · AFFiNE","depth":4,"bounds":{"left":0.5,"top":0.11731844,"width":0.06881649,"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":"All docs · AFFiNE","depth":5,"bounds":{"left":0.51329786,"top":0.12849163,"width":0.029587766,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"bounds":{"left":0.5,"top":0.15003991,"width":0.06881649,"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.51329786,"top":0.16121309,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.5,"top":0.18276137,"width":0.06881649,"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.51329786,"top":0.19393456,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.5,"top":0.21548285,"width":0.06881649,"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.51329786,"top":0.22665602,"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.5,"top":0.2482043,"width":0.06881649,"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.51329786,"top":0.25937748,"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.5,"top":0.28092578,"width":0.06881649,"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":"SQLite Web: db.sqlite","depth":5,"bounds":{"left":0.51329786,"top":0.29209897,"width":0.03756649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.55651593,"top":0.28810853,"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.5028258,"top":0.31524342,"width":0.06333112,"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.5028258,"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.51379657,"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.5249335,"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.53607047,"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.5472075,"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":"sqlite-web 0.7.2","depth":7,"bounds":{"left":0.5678192,"top":0.021548284,"width":0.043218084,"height":0.030726258},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"sqlite-web 0.7.2","depth":8,"bounds":{"left":0.5678192,"top":0.02793296,"width":0.043218084,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"db.sqlite","depth":10,"bounds":{"left":0.6163564,"top":0.021947326,"width":0.023936171,"height":0.029928172},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"db.sqlite","depth":11,"bounds":{"left":0.61901593,"top":0.029928172,"width":0.01861702,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"audio_transcriptions","depth":10,"bounds":{"left":0.6402925,"top":0.029928172,"width":0.04454787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"287 rows, showing page 1","depth":9,"bounds":{"left":0.6861702,"top":0.0311253,"width":0.05069814,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Query","depth":8,"bounds":{"left":0.9700798,"top":0.025139665,"width":0.018284574,"height":0.023543496},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Query","depth":9,"bounds":{"left":0.9730718,"top":0.030726258,"width":0.012300532,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"table name...","depth":7,"bounds":{"left":0.5674867,"top":0.07462091,"width":0.061835106,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"_sqlx_migrations","depth":9,"bounds":{"left":0.5674867,"top":0.09856345,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"_sqlx_migrations","depth":10,"bounds":{"left":0.57081115,"top":0.102553874,"width":0.038896278,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"audio_chunks","depth":9,"bounds":{"left":0.5674867,"top":0.121308856,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"audio_chunks","depth":10,"bounds":{"left":0.57081115,"top":0.12529927,"width":0.031416222,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"audio_tags","depth":9,"bounds":{"left":0.5674867,"top":0.14405426,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"audio_tags","depth":10,"bounds":{"left":0.57081115,"top":0.14804469,"width":0.025099734,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"audio_transcriptions","depth":9,"bounds":{"left":0.5674867,"top":0.16679968,"width":0.06200133,"height":0.02434158},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"audio_transcriptions","depth":10,"bounds":{"left":0.5711436,"top":0.17158818,"width":0.04654255,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"audio_transcriptions_fts (v)","depth":9,"bounds":{"left":0.5674867,"top":0.19114126,"width":0.06200133,"height":0.040702313},"on_screen":true,"help_text":"audio_transcriptions_fts","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"audio_transcriptions_fts","depth":10,"bounds":{"left":0.57081115,"top":0.19513169,"width":0.055352394,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(v)","depth":11,"bounds":{"left":0.57081115,"top":0.21149242,"width":0.004986702,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"audio_transcriptions_...","depth":9,"bounds":{"left":0.5674867,"top":0.23184358,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"audio_transcriptions_fts_config","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"audio_transcriptions_...","depth":10,"bounds":{"left":0.57081115,"top":0.235834,"width":0.053523935,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"audio_transcriptions_...","depth":9,"bounds":{"left":0.5674867,"top":0.254589,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"audio_transcriptions_fts_data","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"audio_transcriptions_...","depth":10,"bounds":{"left":0.57081115,"top":0.2585794,"width":0.053523935,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"audio_transcriptions_...","depth":9,"bounds":{"left":0.5674867,"top":0.2773344,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"audio_transcriptions_fts_idx","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"audio_transcriptions_...","depth":10,"bounds":{"left":0.57081115,"top":0.28132483,"width":0.053523935,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"elements","depth":9,"bounds":{"left":0.5674867,"top":0.30007982,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"elements","depth":10,"bounds":{"left":0.57081115,"top":0.30407023,"width":0.020777926,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"elements_fts (v)","depth":9,"bounds":{"left":0.5674867,"top":0.32282522,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"elements_fts","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"elements_fts","depth":10,"bounds":{"left":0.57081115,"top":0.32681563,"width":0.030917553,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(v)","depth":11,"bounds":{"left":0.60172874,"top":0.32521948,"width":0.004986702,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"elements_fts_config","depth":9,"bounds":{"left":0.5674867,"top":0.34557062,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"elements_fts_config","depth":10,"bounds":{"left":0.57081115,"top":0.34956107,"width":0.04637633,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"elements_fts_data","depth":9,"bounds":{"left":0.5674867,"top":0.36831605,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"elements_fts_data","depth":10,"bounds":{"left":0.57081115,"top":0.37230647,"width":0.042220745,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"elements_fts_idx","depth":9,"bounds":{"left":0.5674867,"top":0.39106146,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"elements_fts_idx","depth":10,"bounds":{"left":0.57081115,"top":0.39505187,"width":0.0390625,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"frames","depth":9,"bounds":{"left":0.5674867,"top":0.41380686,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"frames","depth":10,"bounds":{"left":0.57081115,"top":0.4177973,"width":0.015791224,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"frames_fts (v)","depth":9,"bounds":{"left":0.5674867,"top":0.4365523,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"frames_fts","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"frames_fts","depth":10,"bounds":{"left":0.57081115,"top":0.4405427,"width":0.025930852,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(v)","depth":11,"bounds":{"left":0.59674203,"top":0.43894652,"width":0.004986702,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"frames_fts_config","depth":9,"bounds":{"left":0.5674867,"top":0.4592977,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"frames_fts_config","depth":10,"bounds":{"left":0.57081115,"top":0.4632881,"width":0.04138963,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"frames_fts_data","depth":9,"bounds":{"left":0.5674867,"top":0.4820431,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"frames_fts_data","depth":10,"bounds":{"left":0.57081115,"top":0.48603353,"width":0.03723404,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"frames_fts_idx","depth":9,"bounds":{"left":0.5674867,"top":0.5047885,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"frames_fts_idx","depth":10,"bounds":{"left":0.57081115,"top":0.5087789,"width":0.033909574,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"meetings","depth":9,"bounds":{"left":0.5674867,"top":0.5275339,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"meetings","depth":10,"bounds":{"left":0.57081115,"top":0.53152436,"width":0.020944148,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"memories","depth":9,"bounds":{"left":0.5674867,"top":0.5502793,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"memories","depth":10,"bounds":{"left":0.57081115,"top":0.55426973,"width":0.02244016,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"memories_fts (v)","depth":9,"bounds":{"left":0.5674867,"top":0.57302475,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"memories_fts","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"memories_fts","depth":10,"bounds":{"left":0.57081115,"top":0.57701516,"width":0.032579787,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(v)","depth":11,"bounds":{"left":0.60339093,"top":0.575419,"width":0.004986702,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"memories_fts_config","depth":9,"bounds":{"left":0.5674867,"top":0.5957702,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"memories_fts_config","depth":10,"bounds":{"left":0.57081115,"top":0.5997606,"width":0.048038565,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"memories_fts_data","depth":9,"bounds":{"left":0.5674867,"top":0.61851555,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"memories_fts_data","depth":10,"bounds":{"left":0.57081115,"top":0.62250596,"width":0.043882977,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"memories_fts_idx","depth":9,"bounds":{"left":0.5674867,"top":0.641261,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"memories_fts_idx","depth":10,"bounds":{"left":0.57081115,"top":0.6452514,"width":0.04055851,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ocr_text","depth":9,"bounds":{"left":0.5674867,"top":0.6640064,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ocr_text","depth":10,"bounds":{"left":0.57081115,"top":0.6679968,"width":0.018783245,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"pipe_executions","depth":9,"bounds":{"left":0.5674867,"top":0.6867518,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"pipe_executions","depth":10,"bounds":{"left":0.57081115,"top":0.6907422,"width":0.036901597,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"pipe_scheduler_state","depth":9,"bounds":{"left":0.5674867,"top":0.7094972,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"pipe_scheduler_state","depth":10,"bounds":{"left":0.57081115,"top":0.7134876,"width":0.049035903,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"secrets","depth":9,"bounds":{"left":0.5674867,"top":0.73224264,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"secrets","depth":10,"bounds":{"left":0.57081115,"top":0.73623306,"width":0.016788565,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"speaker_embeddings","depth":9,"bounds":{"left":0.5674867,"top":0.754988,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"speaker_embeddings","depth":10,"bounds":{"left":0.57081115,"top":0.7589784,"width":0.04886968,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"speakers","depth":9,"bounds":{"left":0.5674867,"top":0.77773345,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"speakers","depth":10,"bounds":{"left":0.57081115,"top":0.78172386,"width":0.020611702,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"sqlite_sequence","depth":9,"bounds":{"left":0.5674867,"top":0.8004789,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"sqlite_sequence","depth":10,"bounds":{"left":0.57081115,"top":0.8044693,"width":0.03723404,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"sqlite_stat1","depth":9,"bounds":{"left":0.5674867,"top":0.82322425,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"sqlite_stat1","depth":10,"bounds":{"left":0.57081115,"top":0.82721466,"width":0.025930852,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"sqlite_stat4","depth":9,"bounds":{"left":0.5674867,"top":0.8459697,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"sqlite_stat4","depth":10,"bounds":{"left":0.57081115,"top":0.8499601,"width":0.026595745,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"tags","depth":9,"bounds":{"left":0.5674867,"top":0.8687151,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"tags","depth":10,"bounds":{"left":0.57081115,"top":0.8727055,"width":0.009973404,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ui_events","depth":9,"bounds":{"left":0.5674867,"top":0.8914605,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ui_events","depth":10,"bounds":{"left":0.57081115,"top":0.8954509,"width":0.021775266,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ui_events_fts (v)","depth":9,"bounds":{"left":0.5674867,"top":0.9142059,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"ui_events_fts","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ui_events_fts","depth":10,"bounds":{"left":0.57081115,"top":0.9181963,"width":0.031914894,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(v)","depth":11,"bounds":{"left":0.60272604,"top":0.91660017,"width":0.0048204786,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ui_events_fts_config","depth":9,"bounds":{"left":0.5674867,"top":0.93695134,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ui_events_fts_config","depth":10,"bounds":{"left":0.57081115,"top":0.94094175,"width":0.04737367,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ui_events_fts_data","depth":9,"bounds":{"left":0.5674867,"top":0.9596967,"width":0.06200133,"height":0.022745412},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ui_events_fts_data","depth":10,"bounds":{"left":0.57081115,"top":0.9636871,"width":0.043218084,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ui_events_fts_idx","depth":9,"bounds":{"left":0.5674867,"top":0.98244214,"width":0.06200133,"height":0.01755786},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ui_events_fts_idx","depth":10,"bounds":{"left":0.57081115,"top":0.98643255,"width":0.039893616,"height":0.013567448},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"video_chunks","depth":9,"bounds":{"left":0.5674867,"top":1.0,"width":0.06200133,"height":-0.0051875114},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"video_chunks","depth":10,"bounds":{"left":0.57081115,"top":1.0,"width":0.03125,"height":-0.009177923},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"vision_tags","depth":9,"bounds":{"left":0.5674867,"top":1.0,"width":0.06200133,"height":-0.027933002},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"vision_tags","depth":10,"bounds":{"left":0.57081115,"top":1.0,"width":0.025930852,"height":-0.031923413},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Toggle helper tables","depth":8,"bounds":{"left":0.5674867,"top":1.0,"width":0.04637633,"height":-0.078611374},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Toggle helper tables","depth":9,"bounds":{"left":0.5674867,"top":1.0,"width":0.04637633,"height":-0.078611374},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Structure","depth":9,"bounds":{"left":0.6392952,"top":0.07462091,"width":0.03274601,"height":0.032322425},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Structure","depth":10,"bounds":{"left":0.6449468,"top":0.08339984,"width":0.02144282,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Content","depth":9,"bounds":{"left":0.67204124,"top":0.07462091,"width":0.029421542,"height":0.032322425},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Content","depth":10,"bounds":{"left":0.67769283,"top":0.08339984,"width":0.018118352,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Query","depth":9,"bounds":{"left":0.70146275,"top":0.07462091,"width":0.025265958,"height":0.032322425},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Query","depth":10,"bounds":{"left":0.70711434,"top":0.08339984,"width":0.013962766,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Export","depth":9,"bounds":{"left":0.72672874,"top":0.07462091,"width":0.026097074,"height":0.032322425},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Export","depth":10,"bounds":{"left":0.73238033,"top":0.08339984,"width":0.014793883,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"id","depth":10,"bounds":{"left":0.6409575,"top":0.12609737,"width":0.004155585,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"id","depth":11,"bounds":{"left":0.6409575,"top":0.12609737,"width":0.004155585,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"audio_chunk_id","depth":10,"bounds":{"left":0.64960104,"top":0.12609737,"width":0.034408245,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"audio_chunk_id","depth":11,"bounds":{"left":0.64960104,"top":0.12609737,"width":0.034408245,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"offset_index","depth":10,"bounds":{"left":0.68700135,"top":0.12609737,"width":0.027426861,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"offset_index","depth":11,"bounds":{"left":0.68700135,"top":0.12609737,"width":0.027426861,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"timestamp","depth":10,"bounds":{"left":0.7174202,"top":0.12609737,"width":0.023271276,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"timestamp","depth":11,"bounds":{"left":0.7174202,"top":0.12609737,"width":0.023271276,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"transcription","depth":10,"bounds":{"left":0.78108376,"top":0.12609737,"width":0.028091755,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"transcription","depth":11,"bounds":{"left":0.78108376,"top":0.12609737,"width":0.028091755,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"device","depth":10,"bounds":{"left":0.8121675,"top":0.12609737,"width":0.01412899,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"device","depth":11,"bounds":{"left":0.8121675,"top":0.12609737,"width":0.01412899,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"is_input_device","depth":10,"bounds":{"left":0.8366024,"top":0.12609737,"width":0.034408245,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"is_input_device","depth":11,"bounds":{"left":0.8366024,"top":0.12609737,"width":0.034408245,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"speaker_id","depth":10,"bounds":{"left":0.87400264,"top":0.12609737,"width":0.023769947,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"speaker_id","depth":11,"bounds":{"left":0.87400264,"top":0.12609737,"width":0.023769947,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"transcription_engine","depth":10,"bounds":{"left":0.90076464,"top":0.12609737,"width":0.04537899,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"transcription_engine","depth":11,"bounds":{"left":0.90076464,"top":0.12609737,"width":0.04537899,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"start_time","depth":10,"bounds":{"left":0.94913566,"top":0.12609737,"width":0.022772606,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"start_time","depth":11,"bounds":{"left":0.94913566,"top":0.12609737,"width":0.022772606,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"end_time","depth":10,"bounds":{"left":0.9772274,"top":0.12609737,"width":0.02044548,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"end_time","depth":11,"bounds":{"left":0.9772274,"top":0.12609737,"width":0.02044548,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"text_length","depth":10,"bounds":{"left":1.0,"top":0.12609737,"width":-0.0054854155,"height":0.012769354},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"text_length","depth":11,"bounds":{"left":1.0,"top":0.12609737,"width":-0.0054854155,"height":0.012769354},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"sync_id","depth":10,"bounds":{"left":1.0,"top":0.12609737,"width":-0.033577085,"height":0.012769354},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"sync_id","depth":11,"bounds":{"left":1.0,"top":0.12609737,"width":-0.033577085,"height":0.012769354},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"synced_at","depth":10,"bounds":{"left":1.0,"top":0.12609737,"width":-0.05335772,"height":0.012769354},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"synced_at","depth":11,"bounds":{"left":1.0,"top":0.12609737,"width":-0.05335772,"height":0.012769354},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"redacted_at","depth":10,"bounds":{"left":1.0,"top":0.12609737,"width":-0.07895613,"height":0.012769354},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"redacted_at","depth":11,"bounds":{"left":1.0,"top":0.12609737,"width":-0.07895613,"height":0.012769354},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"bounds":{"left":0.6409575,"top":0.14405426,"width":0.0019946808,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"16","depth":10,"bounds":{"left":0.64960104,"top":0.14405426,"width":0.004654255,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":10,"bounds":{"left":0.68700135,"top":0.14405426,"width":0.0028257978,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2026-05-10T11:10:32+00:00","depth":10,"bounds":{"left":0.7174202,"top":0.14405426,"width":0.058843084,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"We remember, we remember, start.","depth":10,"bounds":{"left":0.78108376,"top":0.14405426,"width":0.021775266,"height":0.07581804},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"bounds":{"left":0.8121675,"top":0.14405426,"width":0.02144282,"height":0.028332002},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"True","depth":10,"bounds":{"left":0.8366024,"top":0.14405426,"width":0.009142287,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"bounds":{"left":0.87400264,"top":0.14405426,"width":0.0019946808,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"WhisperTiny","depth":10,"bounds":{"left":0.90076464,"top":0.14405426,"width":0.025099734,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"21.9150625","depth":10,"bounds":{"left":0.94913566,"top":0.14405426,"width":0.023769947,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"24.8513125","depth":10,"bounds":{"left":0.9772274,"top":0.14405426,"width":0.02277261,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"33","depth":10,"bounds":{"left":1.0,"top":0.14405426,"width":-0.0054854155,"height":0.012769354},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.14565043,"width":-0.033577085,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.14565043,"width":-0.05335772,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.14565043,"width":-0.07895613,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":10,"bounds":{"left":0.6409575,"top":0.22505985,"width":0.0026595744,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"18","depth":10,"bounds":{"left":0.64960104,"top":0.22505985,"width":0.004654255,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":10,"bounds":{"left":0.68700135,"top":0.22505985,"width":0.0028257978,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2026-05-10T11:11:05+00:00","depth":10,"bounds":{"left":0.7174202,"top":0.22505985,"width":0.058344416,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"We'll","depth":10,"bounds":{"left":0.78108376,"top":0.22505985,"width":0.009807181,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"bounds":{"left":0.8121675,"top":0.22505985,"width":0.02144282,"height":0.028332002},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"True","depth":10,"bounds":{"left":0.8366024,"top":0.22505985,"width":0.009142287,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"bounds":{"left":0.87400264,"top":0.22505985,"width":0.0019946808,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"WhisperTiny","depth":10,"bounds":{"left":0.90076464,"top":0.22505985,"width":0.025099734,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12.7519375","depth":10,"bounds":{"left":0.94913566,"top":0.22505985,"width":0.023271276,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22.0669375","depth":10,"bounds":{"left":0.9772274,"top":0.22505985,"width":0.02277261,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5","depth":10,"bounds":{"left":1.0,"top":0.22505985,"width":-0.0054854155,"height":0.012769354},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.22665602,"width":-0.033577085,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.22665602,"width":-0.05335772,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.22665602,"width":-0.07895613,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3","depth":10,"bounds":{"left":0.6409575,"top":0.25897846,"width":0.0028257978,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"21","depth":10,"bounds":{"left":0.64960104,"top":0.25897846,"width":0.004654255,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":10,"bounds":{"left":0.68700135,"top":0.25897846,"width":0.0028257978,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2026-05-10T11:11:35+00:00","depth":10,"bounds":{"left":0.7174202,"top":0.25897846,"width":0.05817819,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"a good job. I don't know how many people are t","depth":10,"bounds":{"left":0.78108376,"top":0.25897846,"width":0.024933511,"height":0.059856344},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"...","depth":10,"bounds":{"left":0.78108376,"top":0.3216281,"width":0.003656915,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...","depth":11,"bounds":{"left":0.78108376,"top":0.3216281,"width":0.003656915,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"bounds":{"left":0.8121675,"top":0.25897846,"width":0.02144282,"height":0.028332002},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"True","depth":10,"bounds":{"left":0.8366024,"top":0.25897846,"width":0.009142287,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"bounds":{"left":0.87400264,"top":0.25897846,"width":0.0019946808,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"WhisperTiny","depth":10,"bounds":{"left":0.90076464,"top":0.25897846,"width":0.025099734,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0.3319375","depth":10,"bounds":{"left":0.94913566,"top":0.25897846,"width":0.021609042,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"29.8631875","depth":10,"bounds":{"left":0.9772274,"top":0.25897846,"width":0.02277261,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"131","depth":10,"bounds":{"left":1.0,"top":0.25897846,"width":-0.0054854155,"height":0.012769354},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.2605746,"width":-0.033577085,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.2605746,"width":-0.05335772,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.2605746,"width":-0.07895613,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4","depth":10,"bounds":{"left":0.6409575,"top":0.339585,"width":0.0028257978,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"23","depth":10,"bounds":{"left":0.64960104,"top":0.339585,"width":0.005319149,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":10,"bounds":{"left":0.68700135,"top":0.339585,"width":0.0028257978,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2026-05-10T11:42:53+00:00","depth":10,"bounds":{"left":0.7174202,"top":0.339585,"width":0.059674203,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"What is the general approach towards transcribing","depth":10,"bounds":{"left":0.78108376,"top":0.339585,"width":0.024268618,"height":0.07581804},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"...","depth":10,"bounds":{"left":0.78108376,"top":0.41819632,"width":0.003656915,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...","depth":11,"bounds":{"left":0.78108376,"top":0.41819632,"width":0.003656915,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"bounds":{"left":0.8121675,"top":0.339585,"width":0.02144282,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"True","depth":10,"bounds":{"left":0.8366024,"top":0.339585,"width":0.009142287,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"bounds":{"left":0.87400264,"top":0.339585,"width":0.0019946808,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"WhisperTiny","depth":10,"bounds":{"left":0.90076464,"top":0.339585,"width":0.025099734,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"19.9238125","depth":10,"bounds":{"left":0.94913566,"top":0.339585,"width":0.023769947,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"24.5475625","depth":10,"bounds":{"left":0.9772274,"top":0.339585,"width":0.02277261,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"51","depth":10,"bounds":{"left":1.0,"top":0.339585,"width":-0.0054854155,"height":0.012769354},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.34118116,"width":-0.033577085,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.34118116,"width":-0.05335772,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.34118116,"width":-0.07895613,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5","depth":10,"bounds":{"left":0.6409575,"top":0.4365523,"width":0.0026595744,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"23","depth":10,"bounds":{"left":0.64960104,"top":0.4365523,"width":0.005319149,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":10,"bounds":{"left":0.68700135,"top":0.4365523,"width":0.0028257978,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2026-05-10T11:42:53+00:00","depth":10,"bounds":{"left":0.7174202,"top":0.4365523,"width":0.059674203,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"delay?","depth":10,"bounds":{"left":0.78108376,"top":0.4365523,"width":0.012965426,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"bounds":{"left":0.8121675,"top":0.4365523,"width":0.02144282,"height":0.028332002},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"True","depth":10,"bounds":{"left":0.8366024,"top":0.4365523,"width":0.009142287,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"bounds":{"left":0.87400264,"top":0.4365523,"width":0.0019946808,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"WhisperTiny","depth":10,"bounds":{"left":0.90076464,"top":0.4365523,"width":0.025099734,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"25.6444375","depth":10,"bounds":{"left":0.94913566,"top":0.4365523,"width":0.025099734,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"26.4713125","depth":10,"bounds":{"left":0.9772274,"top":0.4365523,"width":0.02277261,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"6","depth":10,"bounds":{"left":1.0,"top":0.4365523,"width":-0.0054854155,"height":0.012769354},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.43814844,"width":-0.033577085,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.43814844,"width":-0.05335772,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.43814844,"width":-0.07895613,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"6","depth":10,"bounds":{"left":0.6409575,"top":0.47007182,"width":0.0028257978,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"25","depth":10,"bounds":{"left":0.64960104,"top":0.47007182,"width":0.005319149,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":10,"bounds":{"left":0.68700135,"top":0.47007182,"width":0.0028257978,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2026-05-10T11:43:25+00:00","depth":10,"bounds":{"left":0.7174202,"top":0.47007182,"width":0.059674203,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"What is the play when transcribe is to spread poi","depth":10,"bounds":{"left":0.78108376,"top":0.47007182,"width":0.026595745,"height":0.059856344},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"...","depth":10,"bounds":{"left":0.78108376,"top":0.5331205,"width":0.003656915,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...","depth":11,"bounds":{"left":0.78108376,"top":0.5331205,"width":0.003656915,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"bounds":{"left":0.8121675,"top":0.47007182,"width":0.02144282,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"True","depth":10,"bounds":{"left":0.8366024,"top":0.47007182,"width":0.009142287,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"bounds":{"left":0.87400264,"top":0.47007182,"width":0.0019946808,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"WhisperTiny","depth":10,"bounds":{"left":0.90076464,"top":0.47007182,"width":0.025099734,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2.7450625","depth":10,"bounds":{"left":0.94913566,"top":0.47007182,"width":0.022107713,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"11.2669375","depth":10,"bounds":{"left":0.9772274,"top":0.47007182,"width":0.02277261,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"119","depth":10,"bounds":{"left":1.0,"top":0.47007182,"width":-0.0054854155,"height":0.012769354},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.471668,"width":-0.033577085,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.471668,"width":-0.05335772,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.471668,"width":-0.07895613,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7","depth":10,"bounds":{"left":0.6409575,"top":0.5510774,"width":0.002493351,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"30","depth":10,"bounds":{"left":0.64960104,"top":0.5510774,"width":0.005319149,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":10,"bounds":{"left":0.68700135,"top":0.5510774,"width":0.0028257978,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2026-05-10T11:44:25+00:00","depth":10,"bounds":{"left":0.7174202,"top":0.5510774,"width":0.059674203,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Thank you.","depth":10,"bounds":{"left":0.78108376,"top":0.5510774,"width":0.022273935,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"bounds":{"left":0.8121675,"top":0.5510774,"width":0.02144282,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"True","depth":10,"bounds":{"left":0.8366024,"top":0.5510774,"width":0.009142287,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"bounds":{"left":0.87400264,"top":0.5510774,"width":0.0019946808,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"WhisperTiny","depth":10,"bounds":{"left":0.90076464,"top":0.5510774,"width":0.025099734,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"19.7044375","depth":10,"bounds":{"left":0.94913566,"top":0.5510774,"width":0.024102394,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"29.8631875","depth":10,"bounds":{"left":0.9772274,"top":0.5510774,"width":0.02277261,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"11","depth":10,"bounds":{"left":1.0,"top":0.5510774,"width":-0.0054854155,"height":0.012769354},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.5526736,"width":-0.033577085,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.5526736,"width":-0.05335772,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.5526736,"width":-0.07895613,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8","depth":10,"bounds":{"left":0.6409575,"top":0.584996,"width":0.0028257978,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"31","depth":10,"bounds":{"left":0.64960104,"top":0.584996,"width":0.004654255,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":10,"bounds":{"left":0.68700135,"top":0.584996,"width":0.0028257978,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2026-05-10T11:44:45+00:00","depth":10,"bounds":{"left":0.7174202,"top":0.584996,"width":0.059840426,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"And","depth":10,"bounds":{"left":0.78108376,"top":0.584996,"width":0.007978723,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"System Audio","depth":10,"bounds":{"left":0.8121675,"top":0.584996,"width":0.014960106,"height":0.028332002},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"False","depth":10,"bounds":{"left":0.8366024,"top":0.584996,"width":0.010472074,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"bounds":{"left":0.87400264,"top":0.584996,"width":0.0019946808,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"WhisperTiny","depth":10,"bounds":{"left":0.90076464,"top":0.584996,"width":0.025099734,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"11.9925625","depth":10,"bounds":{"left":0.94913566,"top":0.584996,"width":0.023769947,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22.7588125","depth":10,"bounds":{"left":0.9772274,"top":0.584996,"width":0.02277261,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3","depth":10,"bounds":{"left":1.0,"top":0.584996,"width":-0.0054854155,"height":0.012769354},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.5865922,"width":-0.033577085,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.5865922,"width":-0.05335772,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.5865922,"width":-0.07895613,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"9","depth":10,"bounds":{"left":0.6409575,"top":0.6189146,"width":0.0028257978,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"31","depth":10,"bounds":{"left":0.64960104,"top":0.6189146,"width":0.004654255,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":10,"bounds":{"left":0.68700135,"top":0.6189146,"width":0.0028257978,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2026-05-10T11:44:45+00:00","depth":10,"bounds":{"left":0.7174202,"top":0.6189146,"width":0.059840426,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"going to be going up to you.","depth":10,"bounds":{"left":0.78108376,"top":0.6189146,"width":0.022938829,"height":0.043894652},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"System Audio","depth":10,"bounds":{"left":0.8121675,"top":0.6189146,"width":0.014960106,"height":0.028332002},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"False","depth":10,"bounds":{"left":0.8366024,"top":0.6189146,"width":0.010472074,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"bounds":{"left":0.87400264,"top":0.6189146,"width":0.0019946808,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"WhisperTiny","depth":10,"bounds":{"left":0.90076464,"top":0.6189146,"width":0.025099734,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"25.2731875","depth":10,"bounds":{"left":0.94913566,"top":0.6189146,"width":0.023936171,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"27.1125625","depth":10,"bounds":{"left":0.9772274,"top":0.6189146,"width":0.02277261,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"28","depth":10,"bounds":{"left":1.0,"top":0.6189146,"width":-0.0054854155,"height":0.012769354},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.62051076,"width":-0.033577085,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.62051076,"width":-0.05335772,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.62051076,"width":-0.07895613,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"10","depth":10,"bounds":{"left":0.6409575,"top":0.6683959,"width":0.0048204786,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"32","depth":10,"bounds":{"left":0.64960104,"top":0.6683959,"width":0.005319149,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":10,"bounds":{"left":0.68700135,"top":0.6683959,"width":0.0028257978,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2026-05-10T11:44:55+00:00","depth":10,"bounds":{"left":0.7174202,"top":0.6683959,"width":0.059840426,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I'll be back.","depth":10,"bounds":{"left":0.78108376,"top":0.6683959,"width":0.023105053,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"bounds":{"left":0.8121675,"top":0.6683959,"width":0.02144282,"height":0.028332002},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"True","depth":10,"bounds":{"left":0.8366024,"top":0.6683959,"width":0.009142287,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":10,"bounds":{"left":0.87400264,"top":0.6683959,"width":0.0026595744,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"WhisperTiny","depth":10,"bounds":{"left":0.90076464,"top":0.6683959,"width":0.025099734,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0.0450625","depth":10,"bounds":{"left":0.94913566,"top":0.6683959,"width":0.022606382,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1.6988125","depth":10,"bounds":{"left":0.9772274,"top":0.6683959,"width":0.021276595,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14","depth":10,"bounds":{"left":1.0,"top":0.6683959,"width":-0.0054854155,"height":0.012769354},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.669992,"width":-0.033577085,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.669992,"width":-0.05335772,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"bounds":{"left":1.0,"top":0.669992,"width":-0.07895613,"height":0.011173184},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"11","depth":10,"bounds":{"left":0.6409575,"top":0.70231444,"width":0.0039893617,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"32","depth":10,"bounds":{"left":0.64960104,"top":0.70231444,"width":0.005319149,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":10,"bounds":{"left":0.68700135,"top":0.70231444,"width":0.0028257978,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2026-05-10T11:44:55+00:00","depth":10,"bounds":{"left":0.7174202,"top":0.70231444,"width":0.059840426,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-8105079871263027740
|
8617066795940253657
|
visual_change
|
accessibility
|
NULL
|
New Tab
New Tab
Screenpipe — Archive
Screenpipe — New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
All docs · AFFiNE
All docs · AFFiNE
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
sqlite-web 0.7.2
sqlite-web 0.7.2
db.sqlite
db.sqlite
audio_transcriptions
287 rows, showing page 1
Query
Query
table name...
_sqlx_migrations
_sqlx_migrations
audio_chunks
audio_chunks
audio_tags
audio_tags
audio_transcriptions
audio_transcriptions
audio_transcriptions_fts (v)
audio_transcriptions_fts
(v)
audio_transcriptions_...
audio_transcriptions_...
audio_transcriptions_...
audio_transcriptions_...
audio_transcriptions_...
audio_transcriptions_...
elements
elements
elements_fts (v)
elements_fts
(v)
elements_fts_config
elements_fts_config
elements_fts_data
elements_fts_data
elements_fts_idx
elements_fts_idx
frames
frames
frames_fts (v)
frames_fts
(v)
frames_fts_config
frames_fts_config
frames_fts_data
frames_fts_data
frames_fts_idx
frames_fts_idx
meetings
meetings
memories
memories
memories_fts (v)
memories_fts
(v)
memories_fts_config
memories_fts_config
memories_fts_data
memories_fts_data
memories_fts_idx
memories_fts_idx
ocr_text
ocr_text
pipe_executions
pipe_executions
pipe_scheduler_state
pipe_scheduler_state
secrets
secrets
speaker_embeddings
speaker_embeddings
speakers
speakers
sqlite_sequence
sqlite_sequence
sqlite_stat1
sqlite_stat1
sqlite_stat4
sqlite_stat4
tags
tags
ui_events
ui_events
ui_events_fts (v)
ui_events_fts
(v)
ui_events_fts_config
ui_events_fts_config
ui_events_fts_data
ui_events_fts_data
ui_events_fts_idx
ui_events_fts_idx
video_chunks
video_chunks
vision_tags
vision_tags
Toggle helper tables
Toggle helper tables
Structure
Structure
Content
Content
Query
Query
Export
Export
id
id
audio_chunk_id
audio_chunk_id
offset_index
offset_index
timestamp
timestamp
transcription
transcription
device
device
is_input_device
is_input_device
speaker_id
speaker_id
transcription_engine
transcription_engine
start_time
start_time
end_time
end_time
text_length
text_length
sync_id
sync_id
synced_at
synced_at
redacted_at
redacted_at
1
16
0
2026-05-10T11:10:32+00:00
We remember, we remember, start.
soundcore AeroClip
True
1
WhisperTiny
21.9150625
24.8513125
33
NULL
NULL
NULL
2
18
0
2026-05-10T11:11:05+00:00
We'll
soundcore AeroClip
True
1
WhisperTiny
12.7519375
22.0669375
5
NULL
NULL
NULL
3
21
0
2026-05-10T11:11:35+00:00
a good job. I don't know how many people are t
...
...
soundcore AeroClip
True
1
WhisperTiny
0.3319375
29.8631875
131
NULL
NULL
NULL
4
23
0
2026-05-10T11:42:53+00:00
What is the general approach towards transcribing
...
...
soundcore AeroClip
True
1
WhisperTiny
19.9238125
24.5475625
51
NULL
NULL
NULL
5
23
0
2026-05-10T11:42:53+00:00
delay?
soundcore AeroClip
True
1
WhisperTiny
25.6444375
26.4713125
6
NULL
NULL
NULL
6
25
0
2026-05-10T11:43:25+00:00
What is the play when transcribe is to spread poi
...
...
soundcore AeroClip
True
1
WhisperTiny
2.7450625
11.2669375
119
NULL
NULL
NULL
7
30
0
2026-05-10T11:44:25+00:00
Thank you.
soundcore AeroClip
True
1
WhisperTiny
19.7044375
29.8631875
11
NULL
NULL
NULL
8
31
0
2026-05-10T11:44:45+00:00
And
System Audio
False
1
WhisperTiny
11.9925625
22.7588125
3
NULL
NULL
NULL
9
31
0
2026-05-10T11:44:45+00:00
going to be going up to you.
System Audio
False
1
WhisperTiny
25.2731875
27.1125625
28
NULL
NULL
NULL
10
32
0
2026-05-10T11:44:55+00:00
I'll be back.
soundcore AeroClip
True
2
WhisperTiny
0.0450625
1.6988125
14
NULL
NULL
NULL
11
32
0
2026-05-10T11:44:55+00:00...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
21689
|
948
|
0
|
2026-05-11T18:17:25.225787+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778523445225_m1.jpg...
|
Firefox
|
SQLite Web: db.sqlite — Personal
|
True
|
sqlite.screenpipe.lakylak.xyz/audio_transcriptions sqlite.screenpipe.lakylak.xyz/audio_transcriptions_fts/content/...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
memories_fts_config
New Tab
New Tab
Screenpipe — A memories_fts_config
New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
All docs · AFFiNE
All docs · AFFiNE
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
sqlite-web 0.7.2
sqlite-web 0.7.2
db.sqlite
db.sqlite
audio_transcriptions_fts
287 rows, showing page 1
Query
Query
table name...
_sqlx_migrations
_sqlx_migrations
audio_chunks
audio_chunks
audio_tags
audio_tags
audio_transcriptions
audio_transcriptions
audio_transcriptions_fts (v)
audio_transcriptions_fts
(v)
audio_transcriptions_...
audio_transcriptions_...
audio_transcriptions_...
audio_transcriptions_...
audio_transcriptions_...
audio_transcriptions_...
elements
elements
elements_fts (v)
elements_fts
(v)
elements_fts_config
elements_fts_config
elements_fts_data
elements_fts_data
elements_fts_idx
elements_fts_idx
frames
frames
frames_fts (v)
frames_fts
(v)
frames_fts_config
frames_fts_config
frames_fts_data
frames_fts_data
frames_fts_idx
frames_fts_idx
meetings
meetings
memories
memories
memories_fts (v)
memories_fts
(v)
memories_fts_config
memories_fts_config
memories_fts_data
memories_fts_data
memories_fts_idx
memories_fts_idx
ocr_text
ocr_text
pipe_executions
pipe_executions
pipe_scheduler_state
pipe_scheduler_state
secrets
secrets
speaker_embeddings
speaker_embeddings
speakers
speakers
sqlite_sequence
sqlite_sequence
sqlite_stat1
sqlite_stat1
sqlite_stat4
sqlite_stat4
tags
tags
ui_events
ui_events
ui_events_fts (v)
ui_events_fts
(v)
ui_events_fts_config
ui_events_fts_config
ui_events_fts_data
ui_events_fts_data
ui_events_fts_idx
ui_events_fts_idx
video_chunks
video_chunks
vision_tags
vision_tags
Toggle helper tables
Toggle helper tables
Structure
Structure
Content
Content
Query
Query
Export
Export
transcription
transcription
device
device
speaker_id
speaker_id
We remember, we remember, start.
soundcore AeroClip
1
We'll
soundcore AeroClip
1
a good job. I don't know how many people are t
...
...
soundcore AeroClip
1
What is the general approach towards transcribing
...
...
soundcore AeroClip
1
delay?
soundcore AeroClip
1
What is the play when transcribe is to spread poi
...
...
soundcore AeroClip
1
Thank you.
soundcore AeroClip
1
And
System Audio
1
going to be going up to you.
System Audio
1
I'll be back.
soundcore AeroClip
2
Thank you.
soundcore AeroClip
1
. .
soundcore AeroClip
1
Here, let's see how far we can go. Here.
soundcore AeroClip
3
just like in drift and while I'm driving, tro
...
...
soundcore AeroClip
1
think is my real idea.
soundcore AeroClip
1
it's a bit of a problem. I think it's a bi
...
...
soundcore AeroClip
3
know. It's not the same. It's not the same
...
...
soundcore AeroClip
1
next time. Thanks for watching.
soundcore AeroClip
1
Not sure what's happening in those.
soundcore AeroClip
1
Thank
soundcore AeroClip
1
please. I will talk about it later, as well as som
...
...
soundcore AeroClip
1
then I would like to show it to you. And after
soundcore AeroClip
3
big number
soundcore AeroClip
1
the other.
soundcore AeroClip
1
Thank
soundcore AeroClip
1
have to do.
soundcore AeroClip
1
Oh, me. Bye.
soundcore AeroClip
1
Thank you.
soundcore AeroClip
2
if we need a chance for extra.
soundcore AeroClip
1
That's your favorite, don't you? Yeah, ye
...
...
soundcore AeroClip
1
here. This is the screen.
soundcore AeroClip
1
Thank you.
soundcore AeroClip
1
I'll take a look at the other side. I'll
...
...
soundcore AeroClip
1
cut. That was nice.
soundcore AeroClip
1
Thank you.
soundcore AeroClip
4
Good night.
soundcore AeroClip
1
Thank you.
soundcore AeroClip
1
for your time.
soundcore AeroClip
2
Good night.
soundcore AeroClip
1
Hello. What is that? What is that? What is that?
soundcore AeroClip
1
So, if you want
soundcore AeroClip
1
the right.
soundcore AeroClip
2
You know? Good afternoon.
soundcore AeroClip
2
a little. That's it. No, I'll play
soundcore AeroClip
1
other side of the video.
soundcore AeroClip
1
Thanks for your time.
soundcore AeroClip
2
Thank you. Thank you.
soundcore AeroClip
1
I'm sorry.
soundcore AeroClip
2
Thank you.
soundcore AeroClip
2
and the doing of producing a single hand.
soundcore AeroClip
2
transcription
transcription
We remember, we remember, start.
We'll
a good job. I don't know how many people are t
...
...
What is the general approach towards transcribing...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"memories_fts_config","depth":2,"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":"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":"All docs · AFFiNE","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All docs · AFFiNE","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":"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":"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":true},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","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.48576388,"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.5086806,"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.53194445,"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.5552083,"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.5784722,"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":"sqlite-web 0.7.2","depth":7,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"sqlite-web 0.7.2","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"db.sqlite","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"db.sqlite","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"audio_transcriptions_fts","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"287 rows, showing page 1","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Query","depth":8,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Query","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"table name...","depth":7,"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"_sqlx_migrations","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"_sqlx_migrations","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"audio_chunks","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"audio_chunks","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"audio_tags","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"audio_tags","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"audio_transcriptions","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"audio_transcriptions","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"audio_transcriptions_fts (v)","depth":9,"on_screen":true,"help_text":"audio_transcriptions_fts","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"audio_transcriptions_fts","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(v)","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"audio_transcriptions_...","depth":9,"on_screen":true,"help_text":"audio_transcriptions_fts_config","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"audio_transcriptions_...","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"audio_transcriptions_...","depth":9,"on_screen":true,"help_text":"audio_transcriptions_fts_data","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"audio_transcriptions_...","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"audio_transcriptions_...","depth":9,"on_screen":true,"help_text":"audio_transcriptions_fts_idx","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"audio_transcriptions_...","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"elements","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"elements","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"elements_fts (v)","depth":9,"on_screen":true,"help_text":"elements_fts","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"elements_fts","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(v)","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"elements_fts_config","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"elements_fts_config","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"elements_fts_data","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"elements_fts_data","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"elements_fts_idx","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"elements_fts_idx","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"frames","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"frames","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"frames_fts (v)","depth":9,"on_screen":true,"help_text":"frames_fts","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"frames_fts","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(v)","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"frames_fts_config","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"frames_fts_config","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"frames_fts_data","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"frames_fts_data","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"frames_fts_idx","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"frames_fts_idx","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"meetings","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"meetings","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"memories","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"memories","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"memories_fts (v)","depth":9,"on_screen":true,"help_text":"memories_fts","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"memories_fts","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(v)","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"memories_fts_config","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"memories_fts_config","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"memories_fts_data","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"memories_fts_data","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"memories_fts_idx","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"memories_fts_idx","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ocr_text","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ocr_text","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"pipe_executions","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"pipe_executions","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"pipe_scheduler_state","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"pipe_scheduler_state","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"secrets","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"secrets","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"speaker_embeddings","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"speaker_embeddings","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"speakers","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"speakers","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"sqlite_sequence","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"sqlite_sequence","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"sqlite_stat1","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"sqlite_stat1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"sqlite_stat4","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"sqlite_stat4","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"tags","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"tags","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ui_events","depth":9,"bounds":{"left":0.6340278,"top":0.0,"width":0.13090278,"height":0.031666666},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ui_events","depth":10,"bounds":{"left":0.6409722,"top":0.0,"width":0.04548611,"height":0.020555556},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ui_events_fts (v)","depth":9,"bounds":{"left":0.6340278,"top":0.0,"width":0.13090278,"height":0.031666666},"on_screen":true,"help_text":"ui_events_fts","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ui_events_fts","depth":10,"bounds":{"left":0.6409722,"top":0.0,"width":0.06666667,"height":0.020555556},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(v)","depth":11,"bounds":{"left":0.70763886,"top":0.0,"width":0.010069445,"height":0.015},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ui_events_fts_config","depth":9,"bounds":{"left":0.6340278,"top":0.0,"width":0.13090278,"height":0.031666666},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ui_events_fts_config","depth":10,"bounds":{"left":0.6409722,"top":0.0,"width":0.098958336,"height":0.020555556},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ui_events_fts_data","depth":9,"bounds":{"left":0.6340278,"top":0.0,"width":0.13090278,"height":0.031666666},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ui_events_fts_data","depth":10,"bounds":{"left":0.6409722,"top":0.00055555557,"width":0.090277776,"height":0.020555556},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ui_events_fts_idx","depth":9,"bounds":{"left":0.6340278,"top":0.026666667,"width":0.13090278,"height":0.031666666},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ui_events_fts_idx","depth":10,"bounds":{"left":0.6409722,"top":0.032222223,"width":0.083333336,"height":0.020555556},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"video_chunks","depth":9,"bounds":{"left":0.6340278,"top":0.058333334,"width":0.13090278,"height":0.031666666},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"video_chunks","depth":10,"bounds":{"left":0.6409722,"top":0.06388889,"width":0.06527778,"height":0.020555556},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"vision_tags","depth":9,"bounds":{"left":0.6340278,"top":0.09,"width":0.13090278,"height":0.031666666},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"vision_tags","depth":10,"bounds":{"left":0.6409722,"top":0.09555556,"width":0.054166667,"height":0.020555556},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Toggle helper tables","depth":8,"bounds":{"left":0.6340278,"top":0.16055556,"width":0.096875,"height":0.020555556},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Toggle helper tables","depth":9,"bounds":{"left":0.6340278,"top":0.16055556,"width":0.096875,"height":0.020555556},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Structure","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Structure","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Content","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Content","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Query","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Query","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Export","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Export","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"transcription","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"transcription","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"device","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"device","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"speaker_id","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"speaker_id","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"We remember, we remember, start.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"We'll","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"a good job. I don't know how many people are t","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"...","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"What is the general approach towards transcribing","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"...","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"delay?","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"What is the play when transcribe is to spread poi","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"...","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Thank you.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"And","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"System Audio","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"going to be going up to you.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"System Audio","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I'll be back.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Thank you.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". .","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here, let's see how far we can go. Here.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"just like in drift and while I'm driving, tro","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"...","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"think is my real idea.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"it's a bit of a problem. I think it's a bi","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"...","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"know. It's not the same. It's not the same","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"...","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"next time. Thanks for watching.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Not sure what's happening in those.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Thank","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"please. I will talk about it later, as well as som","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"...","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"then I would like to show it to you. And after","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"big number","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the other.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Thank","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"have to do.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Oh, me. Bye.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Thank you.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if we need a chance for extra.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"That's your favorite, don't you? Yeah, ye","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"...","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"here. This is the screen.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Thank you.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I'll take a look at the other side. I'll","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"...","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cut. That was nice.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Thank you.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Good night.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Thank you.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"for your time.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Good night.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Hello. What is that? What is that? What is that?","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"So, if you want","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the right.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You know? Good afternoon.","depth":10,"bounds":{"left":0.7875,"top":0.0,"width":0.11736111,"height":0.017777778},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"a little. That's it. No, I'll play","depth":10,"bounds":{"left":0.7875,"top":0.0,"width":0.11770833,"height":0.017777778},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"other side of the video.","depth":10,"bounds":{"left":0.7875,"top":0.0,"width":0.09826389,"height":0.017777778},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Thanks for your time.","depth":10,"bounds":{"left":0.7875,"top":0.0,"width":0.090277776,"height":0.017777778},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Thank you. Thank you.","depth":10,"bounds":{"left":0.7875,"top":0.018888889,"width":0.09618056,"height":0.017777778},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I'm sorry.","depth":10,"bounds":{"left":0.7875,"top":0.04388889,"width":0.039583333,"height":0.017777778},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Thank you.","depth":10,"bounds":{"left":0.7875,"top":0.06944445,"width":0.046875,"height":0.017777778},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and the doing of producing a single hand.","depth":10,"bounds":{"left":0.7875,"top":0.094444446,"width":0.17673612,"height":0.017777778},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"soundcore AeroClip","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"transcription","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"transcription","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"We remember, we remember, start.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"We'll","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"a good job. I don't know how many people are t","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"...","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"What is the general approach towards transcribing","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-8104678488133460603
|
-7644886097574188330
|
idle
|
accessibility
|
NULL
|
memories_fts_config
New Tab
New Tab
Screenpipe — A memories_fts_config
New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
All docs · AFFiNE
All docs · AFFiNE
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
sqlite-web 0.7.2
sqlite-web 0.7.2
db.sqlite
db.sqlite
audio_transcriptions_fts
287 rows, showing page 1
Query
Query
table name...
_sqlx_migrations
_sqlx_migrations
audio_chunks
audio_chunks
audio_tags
audio_tags
audio_transcriptions
audio_transcriptions
audio_transcriptions_fts (v)
audio_transcriptions_fts
(v)
audio_transcriptions_...
audio_transcriptions_...
audio_transcriptions_...
audio_transcriptions_...
audio_transcriptions_...
audio_transcriptions_...
elements
elements
elements_fts (v)
elements_fts
(v)
elements_fts_config
elements_fts_config
elements_fts_data
elements_fts_data
elements_fts_idx
elements_fts_idx
frames
frames
frames_fts (v)
frames_fts
(v)
frames_fts_config
frames_fts_config
frames_fts_data
frames_fts_data
frames_fts_idx
frames_fts_idx
meetings
meetings
memories
memories
memories_fts (v)
memories_fts
(v)
memories_fts_config
memories_fts_config
memories_fts_data
memories_fts_data
memories_fts_idx
memories_fts_idx
ocr_text
ocr_text
pipe_executions
pipe_executions
pipe_scheduler_state
pipe_scheduler_state
secrets
secrets
speaker_embeddings
speaker_embeddings
speakers
speakers
sqlite_sequence
sqlite_sequence
sqlite_stat1
sqlite_stat1
sqlite_stat4
sqlite_stat4
tags
tags
ui_events
ui_events
ui_events_fts (v)
ui_events_fts
(v)
ui_events_fts_config
ui_events_fts_config
ui_events_fts_data
ui_events_fts_data
ui_events_fts_idx
ui_events_fts_idx
video_chunks
video_chunks
vision_tags
vision_tags
Toggle helper tables
Toggle helper tables
Structure
Structure
Content
Content
Query
Query
Export
Export
transcription
transcription
device
device
speaker_id
speaker_id
We remember, we remember, start.
soundcore AeroClip
1
We'll
soundcore AeroClip
1
a good job. I don't know how many people are t
...
...
soundcore AeroClip
1
What is the general approach towards transcribing
...
...
soundcore AeroClip
1
delay?
soundcore AeroClip
1
What is the play when transcribe is to spread poi
...
...
soundcore AeroClip
1
Thank you.
soundcore AeroClip
1
And
System Audio
1
going to be going up to you.
System Audio
1
I'll be back.
soundcore AeroClip
2
Thank you.
soundcore AeroClip
1
. .
soundcore AeroClip
1
Here, let's see how far we can go. Here.
soundcore AeroClip
3
just like in drift and while I'm driving, tro
...
...
soundcore AeroClip
1
think is my real idea.
soundcore AeroClip
1
it's a bit of a problem. I think it's a bi
...
...
soundcore AeroClip
3
know. It's not the same. It's not the same
...
...
soundcore AeroClip
1
next time. Thanks for watching.
soundcore AeroClip
1
Not sure what's happening in those.
soundcore AeroClip
1
Thank
soundcore AeroClip
1
please. I will talk about it later, as well as som
...
...
soundcore AeroClip
1
then I would like to show it to you. And after
soundcore AeroClip
3
big number
soundcore AeroClip
1
the other.
soundcore AeroClip
1
Thank
soundcore AeroClip
1
have to do.
soundcore AeroClip
1
Oh, me. Bye.
soundcore AeroClip
1
Thank you.
soundcore AeroClip
2
if we need a chance for extra.
soundcore AeroClip
1
That's your favorite, don't you? Yeah, ye
...
...
soundcore AeroClip
1
here. This is the screen.
soundcore AeroClip
1
Thank you.
soundcore AeroClip
1
I'll take a look at the other side. I'll
...
...
soundcore AeroClip
1
cut. That was nice.
soundcore AeroClip
1
Thank you.
soundcore AeroClip
4
Good night.
soundcore AeroClip
1
Thank you.
soundcore AeroClip
1
for your time.
soundcore AeroClip
2
Good night.
soundcore AeroClip
1
Hello. What is that? What is that? What is that?
soundcore AeroClip
1
So, if you want
soundcore AeroClip
1
the right.
soundcore AeroClip
2
You know? Good afternoon.
soundcore AeroClip
2
a little. That's it. No, I'll play
soundcore AeroClip
1
other side of the video.
soundcore AeroClip
1
Thanks for your time.
soundcore AeroClip
2
Thank you. Thank you.
soundcore AeroClip
1
I'm sorry.
soundcore AeroClip
2
Thank you.
soundcore AeroClip
2
and the doing of producing a single hand.
soundcore AeroClip
2
transcription
transcription
We remember, we remember, start.
We'll
a good job. I don't know how many people are t
...
...
What is the general approach towards transcribing...
|
21687
|
NULL
|
NULL
|
NULL
|
|
27088
|
1124
|
51
|
2026-05-12T14:04:07.541301+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-12/1778 /Users/lukas/.screenpipe/data/data/2026-05-12/1778594647541_m1.jpg...
|
Firefox
|
Work — Mozilla Firefox
|
True
|
jiminny.atlassian.net/browse/JY-20773
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Unnamed Group
TypeError: League\Flysystem\Filesyst Unnamed Group
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
CloudWatch | us-east-2
CloudWatch | us-east-2
Pipelines - jiminny/app
Pipelines - jiminny/app
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
jiminny.atlassian.net/browse/JY-20773
jiminny.atlassian.net/browse/JY-20773
Close tab
JY-20773 fix user pilot tracking for automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking for automated report generated by LakyLak · Pull Request #12024 · jiminny/app
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
[SRD-6793] Les Mills activity types not pulling in - Jira
[SRD-6793] Les Mills activity types not pulling in - Jira
Platform Team - Backlog - Jira
Platform Team - Backlog - Jira
Userpilot | Automated Report Generated
Userpilot | Automated Report Generated
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)...
|
[{"role":"AXButton","text" [{"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":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — 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":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | us-east-2","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | us-east-2","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-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - 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":"[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · 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-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"jiminny.atlassian.net/browse/JY-20773","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"jiminny.atlassian.net/browse/JY-20773","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":"JY-20773 fix user pilot tracking for 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 for 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":"[JY-20776] Automated report - sentry - 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":"[JY-20776] Automated report - sentry - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · 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-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6793] Les Mills activity types not pulling in - 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":"[SRD-6793] Les Mills activity types not pulling in - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Team - Backlog - 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 Team - Backlog - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Automated 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 | Automated Report Generated","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20776] Automated report - sentry - 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":"[JY-20776] Automated report - sentry - Jira","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,"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,"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,"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,"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,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-8100621331296060989
|
-2724164707397044064
|
visual_change
|
accessibility
|
NULL
|
Unnamed Group
TypeError: League\Flysystem\Filesyst Unnamed Group
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
CloudWatch | us-east-2
CloudWatch | us-east-2
Pipelines - jiminny/app
Pipelines - jiminny/app
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
jiminny.atlassian.net/browse/JY-20773
jiminny.atlassian.net/browse/JY-20773
Close tab
JY-20773 fix user pilot tracking for automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking for automated report generated by LakyLak · Pull Request #12024 · jiminny/app
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
[SRD-6793] Les Mills activity types not pulling in - Jira
[SRD-6793] Les Mills activity types not pulling in - Jira
Platform Team - Backlog - Jira
Platform Team - Backlog - Jira
Userpilot | Automated Report Generated
Userpilot | Automated Report Generated
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)...
|
27086
|
NULL
|
NULL
|
NULL
|
|
22348
|
968
|
60
|
2026-05-12T07:02:38.193960+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-12/1778 /Users/lukas/.screenpipe/data/data/2026-05-12/1778569358193_m1.jpg...
|
Firefox
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira — Work...
|
True
|
jiminny.atlassian.net/jira/software/c/projects/JY/ jiminny.atlassian.net/jira/software/c/projects/JY/boards/37?selectedIssue=JY-20625...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
FirefoxFileEditViewHistoryBookmarksProfilesToolsWi FirefoxFileEditViewHistoryBookmarksProfilesToolsWindowHelpDaily - Platform - 3 m leftmeet.google.com/mie-gawc-dsi?authuser=lukas.kovalik%40jiminny.comNikolay Yankov (Presenting, annotating)ChromeViewHistoryHelp*8• Tue 12 May 10:02S• *ProfilesTabWindow1 Pla14 SeMPLIE Jin4 AT:8 JinCliС мс | E3 мсJir8 Jinai|+https://docs.attention.com/mcp/overview#v1-0-0© AWS|X) SSH• Home | Salesforce'Datadog* Claude |3 CircleciA SentryAttentionSearch…XK• Ask AllDocumentationAPl ReferenceChangelogSuper AgentAutonomous chat sessions |CRM Auto Update4 Generate Call InsightsReportsPer-user activity and usage metricsTotal68- Share Snippets from a Call |Cà Send Follow-Up Emails withTemplatesFor a flat, searchable list of every tool with its scope and a one-line description, see theTools Reference.• Leave and Manage |Comments• Generalized Insights |Model Context Protocol (MCP)|Example promptsA few of the things you can ask Claude (or any MCP-compatible LLM) once the connector isenabled. See more examples.@ Attention MCP Server• Authentication [Tools Reference >Example PromptsSearch & analyze"What were the main objectionsprospects raised in calls with Datadogthis quarter?"Coaching"Compare how our top reps handlepricing objections vs. the rest of theteam this month."Attention BuilderOverviewTriggers >Action StepsScorecard configuration"Create a Discovery scorecard withthree criteria — Pain Identification,Ask a question.Workspace admin"Invite [EMAIL] as a SalesRep on the SMB team and add themWorkflow Runs10:02 AM | Daily - PlatformLộ3D All Bookmarks|SupportLog In >= On this pageOverviewQuickstartWhat's availableExample promptsVersion historyFrequently asked questionst.meet.google.comNikolay Yankov (You, presenti...+7d De100% L28• Tue 12 May 10:02:389Galya DimitrovaNikolay Nikolov4 othersStefka StoyanovaLukas Kovalik16:45...
|
NULL
|
-8100362390414373406
|
NULL
|
click
|
ocr
|
NULL
|
FirefoxFileEditViewHistoryBookmarksProfilesToolsWi FirefoxFileEditViewHistoryBookmarksProfilesToolsWindowHelpDaily - Platform - 3 m leftmeet.google.com/mie-gawc-dsi?authuser=lukas.kovalik%40jiminny.comNikolay Yankov (Presenting, annotating)ChromeViewHistoryHelp*8• Tue 12 May 10:02S• *ProfilesTabWindow1 Pla14 SeMPLIE Jin4 AT:8 JinCliС мс | E3 мсJir8 Jinai|+https://docs.attention.com/mcp/overview#v1-0-0© AWS|X) SSH• Home | Salesforce'Datadog* Claude |3 CircleciA SentryAttentionSearch…XK• Ask AllDocumentationAPl ReferenceChangelogSuper AgentAutonomous chat sessions |CRM Auto Update4 Generate Call InsightsReportsPer-user activity and usage metricsTotal68- Share Snippets from a Call |Cà Send Follow-Up Emails withTemplatesFor a flat, searchable list of every tool with its scope and a one-line description, see theTools Reference.• Leave and Manage |Comments• Generalized Insights |Model Context Protocol (MCP)|Example promptsA few of the things you can ask Claude (or any MCP-compatible LLM) once the connector isenabled. See more examples.@ Attention MCP Server• Authentication [Tools Reference >Example PromptsSearch & analyze"What were the main objectionsprospects raised in calls with Datadogthis quarter?"Coaching"Compare how our top reps handlepricing objections vs. the rest of theteam this month."Attention BuilderOverviewTriggers >Action StepsScorecard configuration"Create a Discovery scorecard withthree criteria — Pain Identification,Ask a question.Workspace admin"Invite [EMAIL] as a SalesRep on the SMB team and add themWorkflow Runs10:02 AM | Daily - PlatformLộ3D All Bookmarks|SupportLog In >= On this pageOverviewQuickstartWhat's availableExample promptsVersion historyFrequently asked questionst.meet.google.comNikolay Yankov (You, presenti...+7d De100% L28• Tue 12 May 10:02:389Galya DimitrovaNikolay Nikolov4 othersStefka StoyanovaLukas Kovalik16:45...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
15258
|
683
|
9
|
2026-05-11T06:34:56.651765+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778481296651_m2.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
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
2
65
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
// First try to get Retry-After from response headers
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
if (method_exists($e, 'getResponseBody')) {
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
$policyName = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
if ($policyName === 'TEN_SECONDLY_ROLLING' || $policyName === 'ten_secondly_rolling') {
return 10;
}
if ($policyName === 'SECONDLY' || $policyName === 'secondly') {
return 1;
}
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
$response = $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
$response = $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
//
// $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // "110"
// $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // "109"
// $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // "10000"
// $body = json_decode((string) $response->getBody(), true);
//
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));
return $response;
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
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"}...
|
[{"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":"2","depth":4,"bounds":{"left":0.35605052,"top":0.17478053,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"65","depth":4,"bounds":{"left":0.36602393,"top":0.17478053,"width":0.010305851,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.37832448,"top":0.17478053,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.38763297,"top":0.17478053,"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.17318435,"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.17318435,"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\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager,\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n // First try to get Retry-After from response headers\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n if (method_exists($e, 'getResponseBody')) {\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n $policyName = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n if ($policyName === 'TEN_SECONDLY_ROLLING' || $policyName === 'ten_secondly_rolling') {\n return 10;\n }\n if ($policyName === 'SECONDLY' || $policyName === 'secondly') {\n return 1;\n }\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n $response = $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n $response = $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n//\n// $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // \"110\"\n// $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // \"109\"\n// $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // \"10000\"\n// $body = json_decode((string) $response->getBody(), true);\n//\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));\n\n return $response;\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager,\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n // First try to get Retry-After from response headers\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n if (method_exists($e, 'getResponseBody')) {\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n $policyName = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n if ($policyName === 'TEN_SECONDLY_ROLLING' || $policyName === 'ten_secondly_rolling') {\n return 10;\n }\n if ($policyName === 'SECONDLY' || $policyName === 'secondly') {\n return 1;\n }\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n $response = $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n $response = $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n//\n// $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // \"110\"\n// $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // \"109\"\n// $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // \"10000\"\n// $body = json_decode((string) $response->getBody(), true);\n//\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));\n\n return $response;\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","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}]...
|
-8100171893230810453
|
-2844612687994943388
|
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
2
65
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
// First try to get Retry-After from response headers
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
if (method_exists($e, 'getResponseBody')) {
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
$policyName = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
if ($policyName === 'TEN_SECONDLY_ROLLING' || $policyName === 'ten_secondly_rolling') {
return 10;
}
if ($policyName === 'SECONDLY' || $policyName === 'secondly') {
return 1;
}
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
$response = $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
$response = $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
//
// $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // "110"
// $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // "109"
// $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // "10000"
// $body = json_decode((string) $response->getBody(), true);
//
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));
return $response;
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
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"}...
|
15257
|
NULL
|
NULL
|
NULL
|
|
15472
|
NULL
|
0
|
2026-05-11T06:52:57.831199+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778482377831_m2.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
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
2
65
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
// First try to get Retry-After from response headers
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
if (method_exists($e, 'getResponseBody')) {
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
$policyName = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
if ($policyName === 'TEN_SECONDLY_ROLLING' || $policyName === 'ten_secondly_rolling') {
return 10;
}
if ($policyName === 'SECONDLY' || $policyName === 'secondly') {
return 1;
}
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
$response = $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
$response = $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
//
// $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // "110"
// $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // "109"
// $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // "10000"
// $body = json_decode((string) $response->getBody(), true);
//
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));
return $response;
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
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"}...
|
[{"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":"2","depth":4,"bounds":{"left":0.35605052,"top":0.17478053,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"65","depth":4,"bounds":{"left":0.36602393,"top":0.17478053,"width":0.010305851,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.37832448,"top":0.17478053,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.38763297,"top":0.17478053,"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.17318435,"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.17318435,"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\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager,\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n // First try to get Retry-After from response headers\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n if (method_exists($e, 'getResponseBody')) {\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n $policyName = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n if ($policyName === 'TEN_SECONDLY_ROLLING' || $policyName === 'ten_secondly_rolling') {\n return 10;\n }\n if ($policyName === 'SECONDLY' || $policyName === 'secondly') {\n return 1;\n }\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n $response = $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n $response = $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n//\n// $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // \"110\"\n// $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // \"109\"\n// $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // \"10000\"\n// $body = json_decode((string) $response->getBody(), true);\n//\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));\n\n return $response;\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager,\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n // First try to get Retry-After from response headers\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n if (method_exists($e, 'getResponseBody')) {\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n $policyName = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n if ($policyName === 'TEN_SECONDLY_ROLLING' || $policyName === 'ten_secondly_rolling') {\n return 10;\n }\n if ($policyName === 'SECONDLY' || $policyName === 'secondly') {\n return 1;\n }\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n $response = $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n $response = $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n//\n// $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // \"110\"\n// $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // \"109\"\n// $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // \"10000\"\n// $body = json_decode((string) $response->getBody(), true);\n//\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));\n\n return $response;\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","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}]...
|
-8100171893230810453
|
-2844612687994943388
|
idle
|
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
2
65
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
// First try to get Retry-After from response headers
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
if (method_exists($e, 'getResponseBody')) {
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
$policyName = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
if ($policyName === 'TEN_SECONDLY_ROLLING' || $policyName === 'ten_secondly_rolling') {
return 10;
}
if ($policyName === 'SECONDLY' || $policyName === 'secondly') {
return 1;
}
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
$response = $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
$response = $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
//
// $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // "110"
// $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // "109"
// $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // "10000"
// $body = json_decode((string) $response->getBody(), true);
//
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));
return $response;
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
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"}...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
20271
|
872
|
8
|
2026-05-11T14:49:46.059921+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778510986059_m1.jpg...
|
Code
|
RateLimitException.php (Working Tree) (RateLimitEx RateLimitException.php (Working Tree) (RateLimitException.php) — app — Modified...
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧ Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧G) - 17 pending changes
17
Run and Debug (⇧⌘D)
Remote Explorer
Extensions (⇧⌘X) - 2 require update
2
Testing...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Explorer (⇧⌘E)","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Search (⇧⌘F)","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Source Control (⌃⇧G) - 17 pending changes","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":true},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"17","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Run and Debug (⇧⌘D)","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Remote Explorer","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Extensions (⇧⌘X) - 2 require update","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Testing","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-8099404447194136515
|
-113974737948860024
|
click
|
hybrid
|
NULL
|
Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧ Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧G) - 17 pending changes
17
Run and Debug (⇧⌘D)
Remote Explorer
Extensions (⇧⌘X) - 2 require update
2
Testing
iTerm2ShellEditViewSessionScriptsProfilesWindowHelpAPP (-zsh)-zsh++DOCKER-232,9 +235,11 @@2,- 881DEV (docker)₴2APP (-zsh)84* eparam string SobjectType The object type ('deals', 'companies', 'contacts', 'calls')* @param array<string, mixed› Spayload The search payload with filters, sorts, properties, etc.ereturn array Thesearch response with'results'total', 'paging'keys* @throws RateLimitException When rate limit is hit* @throws HubspotException On API errors* @return array The search response with 'results', 'total','paging' keyspublic function search(string SobjectType, array Spayload): array-zsh>0 ll*5screenpipe"100% <7O ₴68• Mon 11 May 17:49:45T₴1-zshAPPend diff4) app/Console/Commands/JiminnyDebugCommand.php (statement_indentation)begin diff--- /home/jiminny/app/Console/Commands/JiminnyDebugCommand.php+++/home/jiminny/app/Console/Commands/JiminnyDebugCommand.php-359,11 +359,11 @ScrmService = ScrmResolver->prepareCrmService();-//-//for (Si = 0; si < 3; Si++) {if (Si%25 ===0) {Sthis->info("Syncing opportunity {$1}");Sthis->info("Matching contact {$i}");-//-//.ScrmService->syncOpportunity('374720564');if ($i % 25 === 0) {Sthis->info("Syncing opportunity {$1}");Sthis->info("Matching contact {Si}");////ScrmService-›syncOpportunity('374720564');ScrmService-›matchByName('Robot');end diffFixed 4 of 5666 files in 146.870 seconds, 60.00 MB memory usedWhat's next:Try Docker Debug for seamless, persistent debugging tools in any container or image → docker debug docker_lamp_1...
|
20268
|
/Users/lukas/jiminny/app/app/Jobs/Crm/MatchActivit /Users/lukas/jiminny/app/app/Jobs/Crm/MatchActivityCrmData.php...
|
NULL
|
NULL
|
|
22575
|
972
|
55
|
2026-05-12T07:14:10.047631+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-12/1778 /Users/lukas/.screenpipe/data/data/2026-05-12/1778570050047_m1.jpg...
|
Finder
|
Copy
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Copying “CleanShot 2026-05-12 at 09.45.47.mp4” to Copying “CleanShot 2026-05-12 at 09.45.47.mp4” to “2026”
stop progress
67,1 MB of 1,02 GB - Estimating time remaining…...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Copying “CleanShot 2026-05-12 at 09.45.47.mp4” to “2026”","depth":2,"bounds":{"left":0.5416667,"top":0.27222222,"width":0.21736111,"height":0.015555556},"on_screen":true,"automation_id":"_NS:59","role_description":"text"},{"role":"AXButton","text":"stop progress","depth":2,"bounds":{"left":0.76319444,"top":0.28833333,"width":0.009027778,"height":0.014444444},"on_screen":true,"automation_id":"_NS:8","role_description":"button","is_enabled":true,"is_focused":true},{"role":"AXStaticText","text":"67,1 MB of 1,02 GB - Estimating time remaining…","depth":2,"bounds":{"left":0.5416667,"top":0.30444443,"width":0.21736111,"height":0.015555556},"on_screen":true,"automation_id":"_NS:89","role_description":"text"}]...
|
-8098340767154620667
|
-7774738646268010317
|
visual_change
|
accessibility
|
NULL
|
Copying “CleanShot 2026-05-12 at 09.45.47.mp4” to Copying “CleanShot 2026-05-12 at 09.45.47.mp4” to “2026”
stop progress
67,1 MB of 1,02 GB - Estimating time remaining…...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
18829
|
809
|
10
|
2026-05-11T11:52:28.220394+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778500348220_m2.jpg...
|
Code
|
Review rate limit handli… — app
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧ Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧G) - 22 pending changes
22
Run and Debug (⇧⌘D)
Remote Explorer
Extensions (⇧⌘X) - 2 require update
2
Testing
Claude Code
EXPLORER
EXPLORER
Explorer Section: app
Explorer Section: app
APP
Handler.php
HttpBadRequestException.php
HttpBadRequestWithErrorReasonException.php
HttpForbiddenException.php
HttpMethodNotAllowedException.php
HttpNotFoundException.php
HttpSessionExpiredException.php
HttpUnauthorizedException.php
HttpUnsupportedFormatException.php
InvalidArgumentException.php
InvalidDataException.php
InvalidEnumException.php
InvalidFileException.php
InvalidTeamSettingException.php
JobTimeoutException.php
LogicException.php
MaxTeamTrialSizeExceededException.php
ModelNotFoundException.php
NoResultsException.php
NotImplementedException.php
NotSupportedException.php
NumberUnavailableException.php
OperationException.php
OutOfBoundsException.php
QuotaExceededException.php
RateLimitException.php
M
RegistrationInvitationMismatchException.php...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Explorer (⇧⌘E)","depth":19,"bounds":{"left":0.0,"top":0.047885075,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":true},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.057462092,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Search (⇧⌘F)","depth":19,"bounds":{"left":0.0,"top":0.08619314,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.09577015,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Source Control (⌃⇧G) - 22 pending changes","depth":19,"bounds":{"left":0.0,"top":0.1245012,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.13407822,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"22","depth":22,"bounds":{"left":0.007978723,"top":0.1452514,"width":0.0039893617,"height":0.008778931},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.007978723,"top":0.14604948,"width":0.0023271276,"height":0.007980846}},{"char_start":1,"char_count":1,"bounds":{"left":0.009973404,"top":0.14604948,"width":0.0019946808,"height":0.007980846}}],"role_description":"text"},{"role":"AXRadioButton","text":"Run and Debug (⇧⌘D)","depth":19,"bounds":{"left":0.0,"top":0.16280925,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.17238627,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Remote Explorer","depth":19,"bounds":{"left":0.0,"top":0.20111732,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.21069433,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Extensions (⇧⌘X) - 2 require update","depth":19,"bounds":{"left":0.0,"top":0.23942538,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.2490024,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":22,"bounds":{"left":0.009640957,"top":0.2601756,"width":0.0019946808,"height":0.008778931},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Testing","depth":19,"bounds":{"left":0.0,"top":0.27773345,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.28731045,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Claude Code","depth":19,"bounds":{"left":0.0,"top":0.3160415,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"EXPLORER","depth":17,"bounds":{"left":0.022606382,"top":0.047885075,"width":0.018949468,"height":0.02793296},"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"EXPLORER","depth":18,"bounds":{"left":0.022606382,"top":0.056664005,"width":0.018949468,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.022606382,"top":0.056664005,"width":0.0023271276,"height":0.0103751}},{"char_start":1,"char_count":7,"bounds":{"left":0.024933511,"top":0.056664005,"width":0.01662234,"height":0.0103751}}],"role_description":"text"},{"role":"AXButton","text":"Explorer Section: app","depth":21,"bounds":{"left":0.015957447,"top":0.07581804,"width":0.09940159,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.01662234,"top":0.07821229,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"Explorer Section: app","depth":22,"bounds":{"left":0.022606382,"top":0.07581804,"width":0.0076462766,"height":0.017557861},"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"APP","depth":23,"bounds":{"left":0.022606382,"top":0.079010375,"width":0.0076462766,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.023936171,"top":0.0933759,"width":0.0063164895,"height":0.003990423},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Handler.php","depth":27,"bounds":{"left":0.03125,"top":0.0933759,"width":0.024601065,"height":0.0023942539},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.023936171,"top":0.09976058,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HttpBadRequestException.php","depth":27,"bounds":{"left":0.03125,"top":0.101356745,"width":0.061835106,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03125,"top":0.10215483,"width":0.0033244682,"height":0.011971269}},{"char_start":1,"char_count":26,"bounds":{"left":0.034574468,"top":0.10215483,"width":0.058843084,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.023936171,"top":0.11731844,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HttpBadRequestWithErrorReasonException.php","depth":27,"bounds":{"left":0.03125,"top":0.118914604,"width":0.08277926,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03125,"top":0.11971269,"width":0.0033244682,"height":0.011971269}},{"char_start":1,"char_count":41,"bounds":{"left":0.034574468,"top":0.11971269,"width":0.09275266,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.023936171,"top":0.1348763,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HttpForbiddenException.php","depth":27,"bounds":{"left":0.03125,"top":0.13647246,"width":0.05817819,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03125,"top":0.13727055,"width":0.0033244682,"height":0.011971269}},{"char_start":1,"char_count":25,"bounds":{"left":0.034574468,"top":0.13727055,"width":0.054853722,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.023936171,"top":0.15243416,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HttpMethodNotAllowedException.php","depth":27,"bounds":{"left":0.03125,"top":0.15403032,"width":0.076130316,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03125,"top":0.15482841,"width":0.0033244682,"height":0.011971269}},{"char_start":1,"char_count":32,"bounds":{"left":0.034574468,"top":0.15482841,"width":0.07280585,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.023936171,"top":0.16999201,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HttpNotFoundException.php","depth":27,"bounds":{"left":0.03125,"top":0.17158818,"width":0.057513297,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03125,"top":0.17238627,"width":0.0033244682,"height":0.011971269}},{"char_start":1,"char_count":24,"bounds":{"left":0.034574468,"top":0.17238627,"width":0.05418883,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.023936171,"top":0.18754987,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HttpSessionExpiredException.php","depth":27,"bounds":{"left":0.03125,"top":0.18914606,"width":0.068484046,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03125,"top":0.18994413,"width":0.0033244682,"height":0.011971269}},{"char_start":1,"char_count":30,"bounds":{"left":0.034574468,"top":0.18994413,"width":0.065159574,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.023936171,"top":0.20510775,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HttpUnauthorizedException.php","depth":27,"bounds":{"left":0.03125,"top":0.20670392,"width":0.06482713,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03125,"top":0.207502,"width":0.0033244682,"height":0.011971269}},{"char_start":1,"char_count":28,"bounds":{"left":0.034574468,"top":0.207502,"width":0.061502658,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.023936171,"top":0.22266561,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HttpUnsupportedFormatException.php","depth":27,"bounds":{"left":0.03125,"top":0.22426178,"width":0.078457445,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03125,"top":0.22505985,"width":0.0033244682,"height":0.011971269}},{"char_start":1,"char_count":33,"bounds":{"left":0.034574468,"top":0.22505985,"width":0.07513298,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.023936171,"top":0.24022347,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"InvalidArgumentException.php","depth":27,"bounds":{"left":0.03125,"top":0.24181964,"width":0.061502658,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03125,"top":0.24261771,"width":0.0013297872,"height":0.011971269}},{"char_start":1,"char_count":27,"bounds":{"left":0.032579787,"top":0.24261771,"width":0.06017287,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.023936171,"top":0.25778133,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"InvalidDataException.php","depth":27,"bounds":{"left":0.03125,"top":0.25937748,"width":0.05086436,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03125,"top":0.2601756,"width":0.0013297872,"height":0.011971269}},{"char_start":1,"char_count":23,"bounds":{"left":0.032579787,"top":0.2601756,"width":0.049867023,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.023936171,"top":0.2753392,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"InvalidEnumException.php","depth":27,"bounds":{"left":0.03125,"top":0.27693537,"width":0.05285904,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03125,"top":0.27773345,"width":0.0013297872,"height":0.011971269}},{"char_start":1,"char_count":23,"bounds":{"left":0.032579787,"top":0.27773345,"width":0.051529255,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.023936171,"top":0.29289705,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"InvalidFileException.php","depth":27,"bounds":{"left":0.03125,"top":0.29449323,"width":0.048537236,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03125,"top":0.2952913,"width":0.0013297872,"height":0.011971269}},{"char_start":1,"char_count":23,"bounds":{"left":0.032579787,"top":0.2952913,"width":0.047539894,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.023936171,"top":0.3104549,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"InvalidTeamSettingException.php","depth":27,"bounds":{"left":0.03125,"top":0.3120511,"width":0.066821806,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03125,"top":0.31284916,"width":0.0013297872,"height":0.011971269}},{"char_start":1,"char_count":30,"bounds":{"left":0.032579787,"top":0.31284916,"width":0.06549202,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.023936171,"top":0.32801276,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"JobTimeoutException.php","depth":27,"bounds":{"left":0.03125,"top":0.32960895,"width":0.05219415,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03125,"top":0.33040702,"width":0.0023271276,"height":0.011971269}},{"char_start":1,"char_count":22,"bounds":{"left":0.03357713,"top":0.33040702,"width":0.049867023,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.023936171,"top":0.34557062,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"LogicException.php","depth":27,"bounds":{"left":0.03125,"top":0.3471668,"width":0.03956117,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03125,"top":0.34796488,"width":0.0023271276,"height":0.011971269}},{"char_start":1,"char_count":17,"bounds":{"left":0.03357713,"top":0.34796488,"width":0.03723404,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.023936171,"top":0.36312848,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MaxTeamTrialSizeExceededException.php","depth":27,"bounds":{"left":0.03125,"top":0.36472467,"width":0.084109046,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03125,"top":0.36552274,"width":0.0039893617,"height":0.011971269}},{"char_start":1,"char_count":36,"bounds":{"left":0.03523936,"top":0.36552274,"width":0.080119684,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.023936171,"top":0.38068634,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ModelNotFoundException.php","depth":27,"bounds":{"left":0.03125,"top":0.38228253,"width":0.061170213,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03125,"top":0.3830806,"width":0.0039893617,"height":0.011971269}},{"char_start":1,"char_count":25,"bounds":{"left":0.03523936,"top":0.3830806,"width":0.05718085,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.023936171,"top":0.3982442,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"NoResultsException.php","depth":27,"bounds":{"left":0.03125,"top":0.39984038,"width":0.04920213,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03125,"top":0.40063846,"width":0.0033244682,"height":0.011971269}},{"char_start":1,"char_count":21,"bounds":{"left":0.034574468,"top":0.40063846,"width":0.045877658,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.023936171,"top":0.41580206,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"NotImplementedException.php","depth":27,"bounds":{"left":0.03125,"top":0.41739824,"width":0.06216755,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03125,"top":0.41819632,"width":0.0033244682,"height":0.011971269}},{"char_start":1,"char_count":26,"bounds":{"left":0.034574468,"top":0.41819632,"width":0.059175532,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.023936171,"top":0.43335995,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"NotSupportedException.php","depth":27,"bounds":{"left":0.03125,"top":0.4349561,"width":0.05718085,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03125,"top":0.43575418,"width":0.0033244682,"height":0.011971269}},{"char_start":1,"char_count":24,"bounds":{"left":0.034574468,"top":0.43575418,"width":0.053856384,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.023936171,"top":0.4509178,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"NumberUnavailableException.php","depth":27,"bounds":{"left":0.03125,"top":0.45251396,"width":0.06815159,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03125,"top":0.45331204,"width":0.0033244682,"height":0.011971269}},{"char_start":1,"char_count":29,"bounds":{"left":0.034574468,"top":0.45331204,"width":0.06482713,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.023936171,"top":0.46847567,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"OperationException.php","depth":27,"bounds":{"left":0.03125,"top":0.47007182,"width":0.048537236,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03125,"top":0.4708699,"width":0.0033244682,"height":0.011971269}},{"char_start":1,"char_count":21,"bounds":{"left":0.034574468,"top":0.4708699,"width":0.045545213,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.023936171,"top":0.48603353,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"OutOfBoundsException.php","depth":27,"bounds":{"left":0.03125,"top":0.48762968,"width":0.05618351,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03125,"top":0.4884278,"width":0.0033244682,"height":0.011971269}},{"char_start":1,"char_count":23,"bounds":{"left":0.034574468,"top":0.4884278,"width":0.05285904,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.023936171,"top":0.50359136,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"QuotaExceededException.php","depth":27,"bounds":{"left":0.03125,"top":0.5051876,"width":0.06050532,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03125,"top":0.5059856,"width":0.0033244682,"height":0.011971269}},{"char_start":1,"char_count":25,"bounds":{"left":0.034574468,"top":0.5059856,"width":0.057513297,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.023936171,"top":0.5211492,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"RateLimitException.php","depth":27,"bounds":{"left":0.03125,"top":0.52274543,"width":0.047539894,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03125,"top":0.5235435,"width":0.0029920214,"height":0.011971269}},{"char_start":1,"char_count":21,"bounds":{"left":0.034242023,"top":0.5235435,"width":0.04488032,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"M","depth":27,"bounds":{"left":0.10638298,"top":0.5235435,"width":0.003656915,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.023936171,"top":0.5387071,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"RegistrationInvitationMismatchException.php","depth":27,"bounds":{"left":0.03125,"top":0.5403033,"width":0.08277926,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03125,"top":0.54110134,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":42,"bounds":{"left":0.033909574,"top":0.54110134,"width":0.08843085,"height":0.011971269}}],"role_description":"text"}]...
|
-8096533169179651267
|
-4877091080770060020
|
visual_change
|
accessibility
|
NULL
|
Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧ Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧G) - 22 pending changes
22
Run and Debug (⇧⌘D)
Remote Explorer
Extensions (⇧⌘X) - 2 require update
2
Testing
Claude Code
EXPLORER
EXPLORER
Explorer Section: app
Explorer Section: app
APP
Handler.php
HttpBadRequestException.php
HttpBadRequestWithErrorReasonException.php
HttpForbiddenException.php
HttpMethodNotAllowedException.php
HttpNotFoundException.php
HttpSessionExpiredException.php
HttpUnauthorizedException.php
HttpUnsupportedFormatException.php
InvalidArgumentException.php
InvalidDataException.php
InvalidEnumException.php
InvalidFileException.php
InvalidTeamSettingException.php
JobTimeoutException.php
LogicException.php
MaxTeamTrialSizeExceededException.php
ModelNotFoundException.php
NoResultsException.php
NotImplementedException.php
NotSupportedException.php
NumberUnavailableException.php
OperationException.php
OutOfBoundsException.php
QuotaExceededException.php
RateLimitException.php
M
RegistrationInvitationMismatchException.php...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
1091
|
39
|
18
|
2026-05-07T08:00:59.500294+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778140859500_m1.jpg...
|
PhpStorm
|
faVsco.js – console [PROD]
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Code changed:
Hide
Sync Changes
Hide This Notification
37
1
35
63
Previous Highlighted Error
Next Highlighted Error
SELECT * FROM teams WHERE name LIKE '%litify%'; # 1069, 994, 24993
SELECT * FROM users WHERE id = 25061;
SELECT * FROM crm_profiles WHERE crm_configuration_id = 994;
SELECT * FROM crm_profiles WHERE user_id = 25061;
select * from crm_configurations where id = 834;
SELECT * FROM teams WHERE id = 882;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 882 and sa.provider = 'hubspot';
SELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal
SELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 933 and sa.provider = 'hubspot';
SELECT * FROM crm_configurations WHERE provider = 'hubspot' and crm_provider_id = 7270388;
SELECT * FROM contacts where crm_configuration_id = 834;
SELECT * FROM opportunities WHERE team_id = 933
# AND crm_provider_id IN ('20131586060','46017317898','52543911090','53451356564','54101251892','54323768459');
AND id IN (8482561,18352941,19042734,19232139,19445140,19472541);
SELECT * FROM opportunity_contacts
WHERE opportunity_id IN (8482561,18352941,19042734,19232139,19445140,19472541);
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 485; #
SELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 933 and sa.provider = 'hubspot';
select crm.provider, l.* from leads l join crm_configurations crm on l.crm_configuration_id = crm.id
where crm.provider NOT IN ('salesforce', 'integration-app', 'bullhorn', 'copper')
# and l.converted_at IS NOT NULL
;
# [PASSWORD_DOTS]
SELECT * FROM activities a WHERE type IN ('email-inbound', 'email-outbound')
and opportunity_id IS NULL
order by id desc;
SELECT * FROM teams WHERE id = 604; # 598
SELECT * FROM activities WHERE id = 74410828; # [EMAIL]
SELECT * FROM accounts WHERE id = 20068382;
SELECT * FROM accounts WHERE id = 35186038;
SELECT * FROM contacts WHERE team_id = 852 and updated_at > '2026-01-23 12:30:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 559 and sa.provider = 'hubspot';
SELECT * FROM activities WHERE uuid_to_bin('cb6342b6-a183-401c-b0af-ede92b2ae763') = uuid;
select * from sidekick_settings where team_id = 781;
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 26651871; # Teya
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 7562435;
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8420347; # opflit 2100
SELECT * FROM crm_layouts WHERE crm_configuration_id = 711;
SELECT * FROM activities where crm_configuration_id = 711 and crm_provider_id IS NULL
and is_internal = 0 and status = 'completed'
order by id desc;
SELECT * FROM crm_layout_entities
WHERE crm_layout_id IN (2352, 2353);
;
SELECT * FROM crm_configurations where provider = 'hubspot' and id = 530;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 556 and sa.provider = 'hubspot';
SELECT * FROM activities WHERE uuid_to_bin('c6ca4b22-7738-4563-a95d-b8a9598924ae') = uuid;
SELECT * FROM activities WHERE uuid_to_bin('442abb2b-28bd-4be8-9c25-19e9bf02766d') = uuid;
select * from contacts
where crm_configuration_id = 530
and crm_provider_id = 872252;
select * from activities where crm_configuration_id = 530
and user_id = 14343 and type like '%softphone%'
and created_at between '2026-01-28 15:00:00' and '2026-01-28 15:10:00';
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 25666868; # Teya
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8646335; # Teya
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id IN (5933397);
SELECT t.name, t.id, t.owner_id, c.id, c.provider, c.crm_base_url FROM teams t
JOIN crm_configurations c ON t.id = c.team_id
WHERE t.status = 'active';
SELECT * FROM teams where id = 1091;
SELECT * FROM crm_configurations where team_id = 1091;
SELECT * FROM activity_providers where team_id = 1091;
SELECT * FROM activities where crm_configuration_id = 1024 and type IN ('softphone', 'softphone-outbound')
and provider NOT IN ('hubspot', 'aircall')
# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'
order by id desc;
SELECT * FROM teams WHERE name LIKE '%Leadventure%';
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1091 and sa.provider = 'salesforce';
SELECT * FROM teams WHERE name LIKE '%Wilson%'; # 862, 812
SELECT * FROM teams where id = 862;
SELECT * FROM crm_configurations where team_id = 862;
SELECT * FROM activity_providers where team_id = 862;
SELECT * FROM activities where crm_configuration_id = 812 and type IN ('softphone', 'softphone-outbound')
and provider NOT IN ('hubspot', 'aircall')
# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'
order by id desc;
SELECT t.id, crm.id, crm.provider, ap.* FROM teams t
join crm_configurations crm on t.id = crm.team_id
join activity_providers ap on t.id = ap.team_id
where t.status = 'active' and ap.is_enabled = 1
and crm.provider = 'hubspot'
and ap.provider NOT IN ('hubspot', 'aircall', 'uploader', 'gong', 'twilio', 'zoom-bot', 'google-meet', 'ms-teams',
'outreach', 'close', 'ringcentral', 'dialpad', 'zoom-phone');
SELECT * FROM teams where id = 1068;
SELECT * FROM crm_configurations where team_id = 1068;
SELECT * FROM activity_providers where team_id = 1068;
SELECT * FROM activities a
where crm_configuration_id = 993 and type IN ('softphone', 'softphone-outbound')
and a.provider NOT IN ('hubspot', 'uploader', 'gong', 'twilio', 'google-meet', 'ms-teams','close'
)
# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'
order by a.id desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1068 and sa.provider = 'hubspot';
# [PASSWORD_DOTS]
# [PASSWORD_DOTS]
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal , portalId: 6017093
SELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-06 00:00:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 933 and sa.provider = 'hubspot';
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 834; # 882 - AnyVan , portalId: 5468262
SELECT * FROM contacts WHERE crm_configuration_id = 834 and updated_at > '2026-03-30 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE crm_configuration_id = 834 and updated_at > '2026-03-04 08:00:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 882 and sa.provider = 'hubspot';
select * from crm_layouts where crm_configuration_id = 834;
select * from crm_layout_entities where crm_layout_id = 2780;
select * from crm_fields where id IN (321153,321192,321193,321194);
SELECT * FROM opportunities WHERE crm_configuration_id = 834 and id = 10993426;
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 988; # 1057 - Teya (543ce4f4-168c-4571-91ea-5b35c253f06f) , portalId: 26651871
SELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1057 and sa.provider = 'hubspot';
SELECT * FROM crm_configurations where id = 533; # 559 - Connectd , portalId: 6710988
SELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 801; # 852 - Rise Vision , portalId: 2700250
SELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-04 00:00:00' order by updated_at desc; # 6th last
SELECT * FROM crm_configurations where id = 962; # 1034 - evergrowth.io , portalId: 143180990
SELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 1037; # 1102 - Jibble , portalId: 6649755
SELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 8
SELECT * FROM crm_configurations where id = 1015; # 1049 - Travefy , portalId: 48904401
SELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 20
SELECT * FROM crm_configurations where id = 64; # 70 - SalaryFinance , portalId: 3404115
SELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 6th last
SELECT * FROM crm_configurations where id = 802; # 853 - Street Group , portalId: 7658438
SELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 10
SELECT * FROM crm_configurations where id = 872; # 921 - In Professional Development , portalId: 9238273
SELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 2
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 550; # 576 - SeedLegals , portalId: 3028661
SELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 989; # 1058 - rtaoutdoor.com , portalId: 22371204
SELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 896; # 946 - Mintago , portalId: 6621281
SELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 617; # 641 - PCS , portalId: 5244937
SELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-05 14:00:00' order by updated_at desc; # 7th
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 649; # 670 - Eventeny , portalId: 4492849
SELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; #
SELECT * FROM crm_configurations where id = 48; # 51 - CleanCloud , portalId: 4373137
SELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-03-04 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-02-09 08:00:00' order by updated_at desc;
select * from users where team_id = 51; # 7783
SELECT * FROM groups WHERE uuid_to_bin('8a8d2cb6-8b55-4fa3-8b5c-5f0e3d8de59a') = uuid; # 1130
select * from activity_searches where user_id = 7783;
select * from activity_search_filters where activity_search_id IN (32291, 32292);
SELECT asf.activity_search_id, asf.id, asf.value
FROM activity_search_filters asf
WHERE asf.filter = 'group_id'
AND asf.value IN (
SELECT CONCAT(
HEX(SUBSTR(uuid, 5, 4)), '-',
HEX(SUBSTR(uuid, 3, 2)), '-',
HEX(SUBSTR(uuid, 1, 2)), '-',
HEX(SUBSTR(uuid, 9, 2)), '-',
HEX(SUBSTR(uuid, 11))
)
FROM groups
WHERE deleted_at IS NOT NULL
);
SELECT * FROM crm_configurations where id = 272; # 290 - Bonham & Brook , portalId: 5705856
SELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-05 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; # 6th
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where provider = 'hubspot';
SELECT * FROM crm_configurations where id = 1056; # 1119 - Chromatic , portalId: 45602133
SELECT * FROM opportunities WHERE team_id = 1119 and remotely_created_at > '2026-02-01 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1119 and updated_at > '2026-02-09 09:00:00' order by updated_at desc; # null
# [PASSWORD_DOTS]
select * from contacts where crm_provider_id = '003Uu00000ojD4NIAU';
select
cp.*
# DISTINCT t.id
# cp.id, cp.user_id, t.id, cp.crm_configuration_id, cp.contact_fields
FROM crm_profiles cp
JOIN crm_configurations crm on crm.id = cp.crm_configuration_id
JOIN users u on u.id = cp.user_id
JOIN teams t ON t.id = crm.team_id
WHERE crm.provider = 'salesforce' and t.status = 'active'
and cp.archived_at IS NULL and u.deleted_at IS NULL
and t.id NOT IN (1093)
and t.id = 2
and cp.contact_fields IS NULL;
# and c.crm_provider_id = '003Uu00000ojD4NIAU';
SELECT * FROM users WHERE id = 26484;
SELECT * FROM crm_profiles WHERE user_id = 26484;
SELECT * FROM social_accounts WHERE sociable_id = 26484;
SELECT * FROM crm_configurations where provider = 'salesforce';
select * from users where id IN (10022, 10403);
select * from users where team_id IN (526);
select * from teams where id IN (526, 532);
select * from crm_configurations where id IN (500, 516);
select * from crm_profiles where crm_configuration_id IN (500, 516) and user_id IN (10022, 10403);
select * from contacts where crm_configuration_id IN (500, 516) and crm_provider_id = '003Uu00000ojD4NIAU';
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 526 and sa.provider = 'salesforce';
select * from team_settings where team_id IN (526, 532);
select * from users where id IN (22824);
select * from crm_profiles where crm_configuration_id IN (1026);
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1093 and sa.provider = 'salesforce';
select * from teams where id = 1099;
select * from users where id = 29643
select * from activity_processing_states;
SELECT * FROM teams where name LIKE '%Fare%'; # 233
SELECT * FROM opportunities where crm_configuration_id = 215
# and crm_provider_id = 'oppo_ogESZf2P50nDrd1nGPvKDXeA6sSaTN5v51Lp4ayVzKR'
;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1088 and sa.provider = 'hubspot';
SELECT * FROM teams order by updated_at DESC
SELECT * FROM crm_configurations WHERE id = 1019; # SimpleConsign 1088 - no social account
select * from crm_configurations where provider = 'pipedrive';
select * from teams where id = 957;
select * from crm_configurations where id = 957;
SELECT * FROM teams WHERE name LIKE '%Prolific%'; # 544, 518, 10743
SELECT * FROM opportunities where crm_configuration_id = 518 order by id desc;
select * from users where team_id = 1; # 26726 - Gabriela Dureva
SELECT * FROM opportunities where user_id = 26726; # 16834447 - Prolific
select * from activities where user_id = 26726 order by id desc;
select * from contacts where crm_configuration_id = 1
and email IN ('[EMAIL]', '[EMAIL]'); # 2094416, 2093620
SELECT * FROM contacts WHERE id = 6284931;
SELECT p.* FROM activities a JOIN participants p ON a.id = p.activity_id
WHERE a.user_id = 26726 and p.lead_id IN (2094416, 2093620) and a.created_at > '2026-01-01 00:00:00' order by p.email;
select * from activities where id IN (75509259,75509261,75509261,75511034,75026464,75517602,75517605);
select * from crm_configurations where id = 1;
43801692-1aeb-32ce-acba-5b80a479701a
44c3c9cf-6f5e-75f3-8179-bc9f75dd2b1b
405975c0-b3d0-7aaa-821f-09d59cae6dd1
4caf848d-4bed-2299-b248-7788d41f9fca
49bedc3f-f196-eef3-89c3-dea6a3b4aa63
43420989-a09d-b8f8-9806-c8bbf7a02aac
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1 and sa.provider = 'salesforce';
SELECT * FROM activities WHERE id = 75461988;
SELECT * FROM activities WHERE uuid_to_bin('d6c5052e-e972-49e9-8912-26f2f7d6c5f6') = uuid;
select * from contacts where id = 17900517;
select * from contact_roles cr join crm_configurations crm on cr.crm_configuration_id = crm.id
where crm.provider != 'salesforce';
select * from users where id = 21047;
SELECT * FROM crm_configurations WHERE id = 892;
SELECT * FROM teams WHERE id = 942;
select * from opportunities where team_id = 942 order by updated_at desc;
select * from contacts where team_id = 942 order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 942 and sa.provider = 'hubspot';
SELECT * FROM opportunities where team_id = 1 and crm_provider_id IN ('006Pq00000NeH6XIAV', '006Pq000007z8kdIAA'); # 10697889, 6621430
SELECT * FROM crm_configurations WHERE id = 1;
SELECT * FROM teams WHERE crm_id = 1;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1 and sa.provider = 'salesforce';
select id, user_id, opportunity_fields from crm_profiles where crm_configuration_id = 1
SELECT * FROM opportunities where team_id = 1 order by updated_at desc; # 10697889, 6621430
select * from teams where id = 852;
select * from groups where id = 2286;
select * from sidekick_settings where team_id = 852;
select * from default_activity_types where team_id = 852;
SELECT cc.provider, cc.id, p.id, u.*
FROM users u
LEFT JOIN crm_profiles p ON u.id = p.user_id AND p.id IS NULL -- no profile
INNER JOIN teams t ON u.team_id = t.id AND t.status = 'active' -- team is active
INNER JOIN crm_configurations cc ON t.crm_id = cc.id
WHERE u.status = 1 AND u.deleted_at IS NULL
AND u.crm_required = 1
AND u.team_id = 1
ORDER BY u.team_id;
SELECT * FROM crm_profiles cp where cp.crm_configuration_id = 1 and cp.user_id IN (
18481
);
SELECT cc.provider, cc.id, p.id, u.*
FROM users u
LEFT JOIN crm_profiles p ON u.id = p.user_id
INNER JOIN teams t ON u.team_id = t.id AND t.status = 'active'
INNER JOIN crm_configurations cc ON t.crm_id = cc.id
WHERE u.status = 1
AND u.deleted_at IS NULL
AND u.crm_required = 1
# AND u.team_id = 1
AND p.id IS NULL -- Move this condition to WHERE clause
ORDER BY u.team_id;
SELECT * FROM opportunities WHERE id = 20002609;
select * from teams where id = 1122; # Velatir, 29953 - [EMAIL]
select * from crm_configurations where id = 1060;
select * from crm_layouts where crm_configuration_id = 1060;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 3596;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1122 and sa.provider = 'hubspot';
select * from opportunities where team_id = 1122 order by updated_at desc;
select * from crm_field_data where object_type = 'contact';
SELECT * FROM activities WHERE uuid_to_bin('374fc8ed-3315-4c9f-9b25-318b7fd2928f') = uuid; # 76584262
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 248 and sa.provider = 'salesforce';
SELECT * FROM crm_profiles where user_id = 24115; # 005QF000002CswMYAS
SELECT * FROM users where id = 24115;
SELECT * FROM accounts where id = 4002896;
SELECT * FROM teams WHERE name LIKE '%adswerve%';
SELECT * FROM opportunities where crm_configuration_id = 230 AND crm_provider_id IN ("0069N000003GIQ9QAO","0061r000019yGP9AAM","0066900001S2KWlAAN","0066900001TDpj2AAD","0066900001b8uEwAAI","0069N000001rQi0QAE","006QF00000KD40mYAD","006QF00000LzpRJYAZ","0069N000002uomtQAA","0069N000002xlMLQAY","0066900001NV6ubAAD","0061r00001HJp45AAD","006QF00000uTlUoYAK","006QF00000v0bZqYAI");
SELECT * FROM opportunities WHERE crm_configuration_id = 230 AND crm_provider_id = '0069N000003GIQ9QAO'; # 6272203
SELECT u.id, u.email, ac.name, a.* FROM activities a
JOIN users u ON a.user_id = u.id
JOIN accounts ac ON a.account_id = ac.id
WHERE
uuid_to_bin('e3269598-b562-44fb-b5e9-9d2694dc63e0') = a.uuid or
uuid_to_bin('66ddc3ab-4e15-45aa-af0c-248c1eece593') = a.uuid or
uuid_to_bin('826bd328-e1cc-4213-b8d8-572454cacc07') = a.uuid;
select * from users where id = 5825;
SELECT * FROM activities WHERE uuid_to_bin('e56aa2e8-231a-421b-ab1f-cb38ed2bf573') = uuid;
select * from activities where uuid_to_bin('91e13b2f-2d1b-45f8-b1fd-1141b6563782') = uuid;
19594, 862
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 862 and sa.provider = 'salesforce';
select * from automated_reports where id = 36;
select ar.frequency, r.*, ar.* from automated_report_results r
join automated_reports ar on r.report_id = ar.id
where ar.frequency != 'one_off';
select s.* from activity_searches s join users u ON s.user_id = u.id where u.team_id = 882;
select * from nudges n where n.activity_search_id
select * from teams where created_at > '2026-03-09';
SELECT * FROM crm_layouts WHERE crm_configuration_id = 1065; # 1065
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 3617;
select * from users where team_id = 1 and name like '%Lukas%'; # 7160
SELECT * FROM teams WHERE id = 575;
select * from opportunities where team_id = 575;
SELECT * FROM teams WHERE name LIKE '%Integrum ESG%'; # 1126, 1065,
select * from opportunities where team_id = 1126;
SELECT * FROM teams WHERE name LIKE '%Base%'; # 1125, 1063,
select * from opportunities where team_id = 1125;
select * from contacts c
where c.team_id = 882;
SELECT * FROM activities WHERE id = 76822967;
SELECT * FROM crm_profiles WHERE user_id = 15440;
SELECT * FROM crm_profiles WHERE crm_configuration_id = 555;
SELECT * FROM crm_configurations WHERE id = 555;
SELECT * FROM users WHERE id = 15440; # team. 581, gr. 15440, pl. 3911, act. field 162182
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 581 and sa.provider = 'salesforce';
SELECT * FROM automated_report_results order by id desc;
select * from features;
select * from team_features where feature_id = 40;
select * from teams where id = 556;
select * from automated_reports;
where id = 54; # 4fdd41f6-dcf0-30d0-b339-7345381b6044 , ["pdf","podcast"]
SELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;
select * from automated_report_results order by id desc;
SELECT * FROM automated_report_results WHERE id = 1919;
select * from automated_report_results WHERE report_id = 54;
select * from opportunities where id = 7594349;
SELECT * FROM teams WHERE name LIKE '%Les%'; # 711, 692, 16067 - [EMAIL]
select * from playbooks where team_id = 711; # event 226147
SELECT * FROM playbook_categories WHERE playbook_id = 5515;
SELECT * FROM crm_fields WHERE crm_configuration_id = 692 and object_type = 'event';
SELECT * FROM crm_fields WHERE id = 226147;
SELECT * FROM crm_field_values WHERE crm_field_id = 226147;
SELECT * FROM crm_configurations WHERE id = 692;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 711 and sa.provider = 'salesforce';
SELECT * FROM crm_profiles cp JOIN users u on u.id = cp.user_id WHERE u.team_id = 711;
select * from leads;
select * from calendars;
SELECT
t.id AS team_id,
t.name,
LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1)) AS calendar_domain
FROM teams t
JOIN users u ON u.team_id = t.id
JOIN calendars c ON c.user_id = u.id AND c.status = 'active' AND c.calendar_provider_id LIKE '%@%'
LEFT JOIN team_domains td
ON td.team_id = t.id
AND td.deleted_at IS NULL
AND td.domain = LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1))
GROUP BY t.id, t.name, calendar_domain
ORDER BY t.name, calendar_domain;
select * from users u join calendars c on c.user_id = u.id
where u.team_id = 882;
select * from activities where id = 74049485; # team 563 crm 537
select * from activities where id = 73272382; # team 563 crm 537
select * from activities where id = 64400389; # team 563 crm 537
select * from activities where id = 58081273; # team 563 crm 537
select * from activities where id = 54520297; # team 563 crm 537
select * from participants where activity_id = 58081273;
select * from activities where crm_configuration_id = 537 and provider = 'aircall'
and account_id = 19003658 order by updated_at desc;
select * from contacts where crm_configuration_id = 537 and id = 35957759;
select * from accounts where crm_configuration_id = 537 and id = 19003658;
select * from automated_report_results where id = 1976;
select * from automated_reports where id = 583;
select * from activity_searches where id = 87714;
select * from activity_search_filters where activity_search_id = 87714;
SELECT * FROM activities WHERE uuid_to_bin('8827f672-202d-4162-9d04-73ff5f0566a9') = uuid
or uuid_to_bin('47842446-af51-4bcb-854f-cc6560290101') = uuid;
Sync Changes
Hide This Notification
Code changed:
Hide
4
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands\Dev;
use Jiminny\Console\Commands\Command;
use Jiminny\Contracts\Http\RateLimited;
use Jiminny\Models\Activity\Provider;
use Jiminny\Models\Crm\Configuration;
class AddRateLimitCommand extends Command
{
private const TYPE_ACTIVITY_PROVIDER = Provider::class;
private const TYPE_CRM_CONFIGURATION = Configuration::class;
private const RATE_LIMITED_TYPES = [self::TYPE_ACTIVITY_PROVIDER, self::TYPE_CRM_CONFIGURATION];
protected $signature = 'jiminny:add-rate-limit';
public function handle(): void
{
$type = $this->choice('Choose type', self::RATE_LIMITED_TYPES);
$id = $this->ask(sprintf('Enter an ID of the %s', $type));
$quota = (int) $this->ask('Enter number of requests');
$window = (int) $this->ask('Enter request window in seconds');
$rateLimited = (new $type())::find($id);
if (! $rateLimited instanceof RateLimited) {
$this->error('Model not found');
return;
}
$rateLimited->rateLimits()->updateOrCreate([
'limited_id' => $id,
'limited_type' => $type,
'quota' => $quota,
'window' => $window,
]);
$this->info('Done');
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl, folder
ActionItems, folder
Activity, folder
ActivityAnalytics, folder
ActivitySearch, folder
AiActivityType, folder
AiAutomation, folder
AiCallScoring, folder
AskAnything, folder
Dtos, folder
Events, folder
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi, folder
AWS, folder
BillingManagement, folder
Cache, folder
CoachingFeedback, folder
Country, folder
CustomerApi, folder
Database, folder
Datadog, folder
DateTime, folder
DealInsights, folder
DealRisks, folder
ElasticSearch, folder
Eloquent, folder
Encoding, folder
Encryption, folder
ES, folder
Faker, folder
FeatureFlags, folder
FFMpeg, folder
FileSystem, folder
Gecko, folder
Gong, folder
GuzzleHttp, folder
KeyPoints, folder
Kiosk, folder
LanguageDetection, folder
LiveFeed, folder
Locks, folder
Math, folder
MediaPipeline, folder
MeetingBot, folder
MobileSettings, folder
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage, folder
Playlist, folder
Prophet, folder
ProphetAi, folder
ProsperWorks, folder...
|
[{"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":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master","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":"Execute","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","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":"37","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"35","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"63","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":"SELECT * FROM teams WHERE name LIKE '%litify%'; # 1069, 994, 24993\nSELECT * FROM users WHERE id = 25061;\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 994;\nSELECT * FROM crm_profiles WHERE user_id = 25061;\n\nselect * from crm_configurations where id = 834;\nSELECT * FROM teams WHERE id = 882;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 882 and sa.provider = 'hubspot';\n\nSELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal\nSELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 933 and sa.provider = 'hubspot';\n\nSELECT * FROM crm_configurations WHERE provider = 'hubspot' and crm_provider_id = 7270388;\n\nSELECT * FROM contacts where crm_configuration_id = 834;\nSELECT * FROM opportunities WHERE team_id = 933\n# AND crm_provider_id IN ('20131586060','46017317898','52543911090','53451356564','54101251892','54323768459');\nAND id IN (8482561,18352941,19042734,19232139,19445140,19472541);\nSELECT * FROM opportunity_contacts\nWHERE opportunity_id IN (8482561,18352941,19042734,19232139,19445140,19472541);\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 485; #\nSELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 933 and sa.provider = 'hubspot';\n\nselect crm.provider, l.* from leads l join crm_configurations crm on l.crm_configuration_id = crm.id\nwhere crm.provider NOT IN ('salesforce', 'integration-app', 'bullhorn', 'copper')\n# and l.converted_at IS NOT NULL\n;\n\n# ********************************************************************\nSELECT * FROM activities a WHERE type IN ('email-inbound', 'email-outbound')\nand opportunity_id IS NULL\norder by id desc;\n\nSELECT * FROM teams WHERE id = 604; # 598\nSELECT * FROM activities WHERE id = 74410828; # chelseaw@allvoices.co\nSELECT * FROM accounts WHERE id = 20068382;\nSELECT * FROM accounts WHERE id = 35186038;\n\nSELECT * FROM contacts WHERE team_id = 852 and updated_at > '2026-01-23 12:30:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 559 and sa.provider = 'hubspot';\n\nSELECT * FROM activities WHERE uuid_to_bin('cb6342b6-a183-401c-b0af-ede92b2ae763') = uuid;\nselect * from sidekick_settings where team_id = 781;\n\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 26651871; # Teya\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 7562435;\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8420347; # opflit 2100\n\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 711;\nSELECT * FROM activities where crm_configuration_id = 711 and crm_provider_id IS NULL\nand is_internal = 0 and status = 'completed'\norder by id desc;\n\nSELECT * FROM crm_layout_entities\nWHERE crm_layout_id IN (2352, 2353);\n;\n\nSELECT * FROM crm_configurations where provider = 'hubspot' and id = 530;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 556 and sa.provider = 'hubspot';\n\nSELECT * FROM activities WHERE uuid_to_bin('c6ca4b22-7738-4563-a95d-b8a9598924ae') = uuid;\nSELECT * FROM activities WHERE uuid_to_bin('442abb2b-28bd-4be8-9c25-19e9bf02766d') = uuid;\nselect * from contacts\nwhere crm_configuration_id = 530\nand crm_provider_id = 872252;\n\nselect * from activities where crm_configuration_id = 530\nand user_id = 14343 and type like '%softphone%'\nand created_at between '2026-01-28 15:00:00' and '2026-01-28 15:10:00';\n\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 25666868; # Teya\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8646335; # Teya\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id IN (5933397);\n\n\nSELECT t.name, t.id, t.owner_id, c.id, c.provider, c.crm_base_url FROM teams t\nJOIN crm_configurations c ON t.id = c.team_id\nWHERE t.status = 'active';\n\nSELECT * FROM teams where id = 1091;\nSELECT * FROM crm_configurations where team_id = 1091;\nSELECT * FROM activity_providers where team_id = 1091;\nSELECT * FROM activities where crm_configuration_id = 1024 and type IN ('softphone', 'softphone-outbound')\nand provider NOT IN ('hubspot', 'aircall')\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by id desc;\n\n\nSELECT * FROM teams WHERE name LIKE '%Leadventure%';\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1091 and sa.provider = 'salesforce';\n\nSELECT * FROM teams WHERE name LIKE '%Wilson%'; # 862, 812\nSELECT * FROM teams where id = 862;\nSELECT * FROM crm_configurations where team_id = 862;\nSELECT * FROM activity_providers where team_id = 862;\nSELECT * FROM activities where crm_configuration_id = 812 and type IN ('softphone', 'softphone-outbound')\nand provider NOT IN ('hubspot', 'aircall')\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by id desc;\n\n\nSELECT t.id, crm.id, crm.provider, ap.* FROM teams t\njoin crm_configurations crm on t.id = crm.team_id\njoin activity_providers ap on t.id = ap.team_id\nwhere t.status = 'active' and ap.is_enabled = 1\nand crm.provider = 'hubspot'\nand ap.provider NOT IN ('hubspot', 'aircall', 'uploader', 'gong', 'twilio', 'zoom-bot', 'google-meet', 'ms-teams',\n 'outreach', 'close', 'ringcentral', 'dialpad', 'zoom-phone');\n\nSELECT * FROM teams where id = 1068;\nSELECT * FROM crm_configurations where team_id = 1068;\nSELECT * FROM activity_providers where team_id = 1068;\n\nSELECT * FROM activities a\nwhere crm_configuration_id = 993 and type IN ('softphone', 'softphone-outbound')\nand a.provider NOT IN ('hubspot', 'uploader', 'gong', 'twilio', 'google-meet', 'ms-teams','close'\n )\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by a.id desc;\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1068 and sa.provider = 'hubspot';\n\n# ********************************************************************\n# ********************************************************************\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal , portalId: 6017093\nSELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-06 00:00:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 933 and sa.provider = 'hubspot';\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 834; # 882 - AnyVan , portalId: 5468262\nSELECT * FROM contacts WHERE crm_configuration_id = 834 and updated_at > '2026-03-30 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE crm_configuration_id = 834 and updated_at > '2026-03-04 08:00:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 882 and sa.provider = 'hubspot';\nselect * from crm_layouts where crm_configuration_id = 834;\nselect * from crm_layout_entities where crm_layout_id = 2780;\nselect * from crm_fields where id IN (321153,321192,321193,321194);\n\nSELECT * FROM opportunities WHERE crm_configuration_id = 834 and id = 10993426;\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 988; # 1057 - Teya (543ce4f4-168c-4571-91ea-5b35c253f06f) , portalId: 26651871\nSELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1057 and sa.provider = 'hubspot';\n\nSELECT * FROM crm_configurations where id = 533; # 559 - Connectd , portalId: 6710988\nSELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 801; # 852 - Rise Vision , portalId: 2700250\nSELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-04 00:00:00' order by updated_at desc; # 6th last\n\nSELECT * FROM crm_configurations where id = 962; # 1034 - evergrowth.io , portalId: 143180990\nSELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 1037; # 1102 - Jibble , portalId: 6649755\nSELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 8\n\nSELECT * FROM crm_configurations where id = 1015; # 1049 - Travefy , portalId: 48904401\nSELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 20\n\nSELECT * FROM crm_configurations where id = 64; # 70 - SalaryFinance , portalId: 3404115\nSELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 6th last\n\nSELECT * FROM crm_configurations where id = 802; # 853 - Street Group , portalId: 7658438\nSELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 10\n\nSELECT * FROM crm_configurations where id = 872; # 921 - In Professional Development , portalId: 9238273\nSELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 2\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 550; # 576 - SeedLegals , portalId: 3028661\nSELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 989; # 1058 - rtaoutdoor.com , portalId: 22371204\nSELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 896; # 946 - Mintago , portalId: 6621281\nSELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 617; # 641 - PCS , portalId: 5244937\nSELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-05 14:00:00' order by updated_at desc; # 7th\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 649; # 670 - Eventeny , portalId: 4492849\nSELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; #\n\nSELECT * FROM crm_configurations where id = 48; # 51 - CleanCloud , portalId: 4373137\nSELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-03-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-02-09 08:00:00' order by updated_at desc;\nselect * from users where team_id = 51; # 7783\nSELECT * FROM groups WHERE uuid_to_bin('8a8d2cb6-8b55-4fa3-8b5c-5f0e3d8de59a') = uuid; # 1130\nselect * from activity_searches where user_id = 7783;\nselect * from activity_search_filters where activity_search_id IN (32291, 32292);\n\nSELECT asf.activity_search_id, asf.id, asf.value\nFROM activity_search_filters asf\nWHERE asf.filter = 'group_id'\nAND asf.value IN (\n SELECT CONCAT(\n HEX(SUBSTR(uuid, 5, 4)), '-',\n HEX(SUBSTR(uuid, 3, 2)), '-',\n HEX(SUBSTR(uuid, 1, 2)), '-',\n HEX(SUBSTR(uuid, 9, 2)), '-',\n HEX(SUBSTR(uuid, 11))\n )\n FROM groups\n WHERE deleted_at IS NOT NULL\n);\n\nSELECT * FROM crm_configurations where id = 272; # 290 - Bonham & Brook , portalId: 5705856\nSELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-05 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; # 6th\n# ********************************************************************\nSELECT * FROM crm_configurations where provider = 'hubspot';\nSELECT * FROM crm_configurations where id = 1056; # 1119 - Chromatic , portalId: 45602133\nSELECT * FROM opportunities WHERE team_id = 1119 and remotely_created_at > '2026-02-01 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1119 and updated_at > '2026-02-09 09:00:00' order by updated_at desc; # null\n# ********************************************************************\n\nselect * from contacts where crm_provider_id = '003Uu00000ojD4NIAU';\nselect\n cp.*\n# DISTINCT t.id\n# cp.id, cp.user_id, t.id, cp.crm_configuration_id, cp.contact_fields\nFROM crm_profiles cp\nJOIN crm_configurations crm on crm.id = cp.crm_configuration_id\nJOIN users u on u.id = cp.user_id\nJOIN teams t ON t.id = crm.team_id\nWHERE crm.provider = 'salesforce' and t.status = 'active'\n and cp.archived_at IS NULL and u.deleted_at IS NULL\n and t.id NOT IN (1093)\n and t.id = 2\n and cp.contact_fields IS NULL;\n# and c.crm_provider_id = '003Uu00000ojD4NIAU';\n\nSELECT * FROM users WHERE id = 26484;\nSELECT * FROM crm_profiles WHERE user_id = 26484;\nSELECT * FROM social_accounts WHERE sociable_id = 26484;\nSELECT * FROM crm_configurations where provider = 'salesforce';\nselect * from users where id IN (10022, 10403);\nselect * from users where team_id IN (526);\nselect * from teams where id IN (526, 532);\nselect * from crm_configurations where id IN (500, 516);\nselect * from crm_profiles where crm_configuration_id IN (500, 516) and user_id IN (10022, 10403);\nselect * from contacts where crm_configuration_id IN (500, 516) and crm_provider_id = '003Uu00000ojD4NIAU';\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 526 and sa.provider = 'salesforce';\nselect * from team_settings where team_id IN (526, 532);\n\nselect * from users where id IN (22824);\nselect * from crm_profiles where crm_configuration_id IN (1026);\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1093 and sa.provider = 'salesforce';\n\nselect * from teams where id = 1099;\nselect * from users where id = 29643\n\nselect * from activity_processing_states;\n\nSELECT * FROM teams where name LIKE '%Fare%'; # 233\nSELECT * FROM opportunities where crm_configuration_id = 215\n# and crm_provider_id = 'oppo_ogESZf2P50nDrd1nGPvKDXeA6sSaTN5v51Lp4ayVzKR'\n;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1088 and sa.provider = 'hubspot';\n\nSELECT * FROM teams order by updated_at DESC\nSELECT * FROM crm_configurations WHERE id = 1019; # SimpleConsign 1088 - no social account\n\nselect * from crm_configurations where provider = 'pipedrive';\n\nselect * from teams where id = 957;\nselect * from crm_configurations where id = 957;\n\nSELECT * FROM teams WHERE name LIKE '%Prolific%'; # 544, 518, 10743\nSELECT * FROM opportunities where crm_configuration_id = 518 order by id desc;\n\nselect * from users where team_id = 1; # 26726 - Gabriela Dureva\nSELECT * FROM opportunities where user_id = 26726; # 16834447 - Prolific\nselect * from activities where user_id = 26726 order by id desc;\nselect * from contacts where crm_configuration_id = 1\nand email IN ('charlotte.ward@prolific.com', 'frankie.bryant@prolific.com'); # 2094416, 2093620\nSELECT * FROM contacts WHERE id = 6284931;\n\nSELECT p.* FROM activities a JOIN participants p ON a.id = p.activity_id\nWHERE a.user_id = 26726 and p.lead_id IN (2094416, 2093620) and a.created_at > '2026-01-01 00:00:00' order by p.email;\n\nselect * from activities where id IN (75509259,75509261,75509261,75511034,75026464,75517602,75517605);\nselect * from crm_configurations where id = 1;\n\n43801692-1aeb-32ce-acba-5b80a479701a\n44c3c9cf-6f5e-75f3-8179-bc9f75dd2b1b\n405975c0-b3d0-7aaa-821f-09d59cae6dd1\n4caf848d-4bed-2299-b248-7788d41f9fca\n49bedc3f-f196-eef3-89c3-dea6a3b4aa63\n43420989-a09d-b8f8-9806-c8bbf7a02aac\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1 and sa.provider = 'salesforce';\n\nSELECT * FROM activities WHERE id = 75461988;\n\nSELECT * FROM activities WHERE uuid_to_bin('d6c5052e-e972-49e9-8912-26f2f7d6c5f6') = uuid;\n\nselect * from contacts where id = 17900517;\n\nselect * from contact_roles cr join crm_configurations crm on cr.crm_configuration_id = crm.id\nwhere crm.provider != 'salesforce';\n\nselect * from users where id = 21047;\nSELECT * FROM crm_configurations WHERE id = 892;\nSELECT * FROM teams WHERE id = 942;\nselect * from opportunities where team_id = 942 order by updated_at desc;\nselect * from contacts where team_id = 942 order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 942 and sa.provider = 'hubspot';\n\nSELECT * FROM opportunities where team_id = 1 and crm_provider_id IN ('006Pq00000NeH6XIAV', '006Pq000007z8kdIAA'); # 10697889, 6621430\nSELECT * FROM crm_configurations WHERE id = 1;\nSELECT * FROM teams WHERE crm_id = 1;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1 and sa.provider = 'salesforce';\n\nselect id, user_id, opportunity_fields from crm_profiles where crm_configuration_id = 1\nSELECT * FROM opportunities where team_id = 1 order by updated_at desc; # 10697889, 6621430\n\nselect * from teams where id = 852;\nselect * from groups where id = 2286;\nselect * from sidekick_settings where team_id = 852;\nselect * from default_activity_types where team_id = 852;\n\n\nSELECT cc.provider, cc.id, p.id, u.*\nFROM users u\nLEFT JOIN crm_profiles p ON u.id = p.user_id AND p.id IS NULL -- no profile\nINNER JOIN teams t ON u.team_id = t.id AND t.status = 'active' -- team is active\nINNER JOIN crm_configurations cc ON t.crm_id = cc.id\nWHERE u.status = 1 AND u.deleted_at IS NULL\nAND u.crm_required = 1\nAND u.team_id = 1\nORDER BY u.team_id;\n\nSELECT * FROM crm_profiles cp where cp.crm_configuration_id = 1 and cp.user_id IN (\n18481\n );\n\nSELECT cc.provider, cc.id, p.id, u.*\nFROM users u\nLEFT JOIN crm_profiles p ON u.id = p.user_id\nINNER JOIN teams t ON u.team_id = t.id AND t.status = 'active'\nINNER JOIN crm_configurations cc ON t.crm_id = cc.id\nWHERE u.status = 1\n AND u.deleted_at IS NULL\n AND u.crm_required = 1\n# AND u.team_id = 1\n AND p.id IS NULL -- Move this condition to WHERE clause\nORDER BY u.team_id;\n\nSELECT * FROM opportunities WHERE id = 20002609;\nselect * from teams where id = 1122; # Velatir, 29953 - christian@velatir.com\nselect * from crm_configurations where id = 1060;\nselect * from crm_layouts where crm_configuration_id = 1060;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 3596;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1122 and sa.provider = 'hubspot';\nselect * from opportunities where team_id = 1122 order by updated_at desc;\n\nselect * from crm_field_data where object_type = 'contact';\n\nSELECT * FROM activities WHERE uuid_to_bin('374fc8ed-3315-4c9f-9b25-318b7fd2928f') = uuid; # 76584262\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 248 and sa.provider = 'salesforce';\n\nSELECT * FROM crm_profiles where user_id = 24115; # 005QF000002CswMYAS\nSELECT * FROM users where id = 24115;\nSELECT * FROM accounts where id = 4002896;\nSELECT * FROM teams WHERE name LIKE '%adswerve%';\nSELECT * FROM opportunities where crm_configuration_id = 230 AND crm_provider_id IN (\"0069N000003GIQ9QAO\",\"0061r000019yGP9AAM\",\"0066900001S2KWlAAN\",\"0066900001TDpj2AAD\",\"0066900001b8uEwAAI\",\"0069N000001rQi0QAE\",\"006QF00000KD40mYAD\",\"006QF00000LzpRJYAZ\",\"0069N000002uomtQAA\",\"0069N000002xlMLQAY\",\"0066900001NV6ubAAD\",\"0061r00001HJp45AAD\",\"006QF00000uTlUoYAK\",\"006QF00000v0bZqYAI\");\nSELECT * FROM opportunities WHERE crm_configuration_id = 230 AND crm_provider_id = '0069N000003GIQ9QAO'; # 6272203\n\nSELECT u.id, u.email, ac.name, a.* FROM activities a\nJOIN users u ON a.user_id = u.id\nJOIN accounts ac ON a.account_id = ac.id\nWHERE\nuuid_to_bin('e3269598-b562-44fb-b5e9-9d2694dc63e0') = a.uuid or\nuuid_to_bin('66ddc3ab-4e15-45aa-af0c-248c1eece593') = a.uuid or\nuuid_to_bin('826bd328-e1cc-4213-b8d8-572454cacc07') = a.uuid;\n\nselect * from users where id = 5825;\nSELECT * FROM activities WHERE uuid_to_bin('e56aa2e8-231a-421b-ab1f-cb38ed2bf573') = uuid;\n\nselect * from activities where uuid_to_bin('91e13b2f-2d1b-45f8-b1fd-1141b6563782') = uuid;\n19594, 862\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 862 and sa.provider = 'salesforce';\n\nselect * from automated_reports where id = 36;\nselect ar.frequency, r.*, ar.* from automated_report_results r\njoin automated_reports ar on r.report_id = ar.id\nwhere ar.frequency != 'one_off';\n\nselect s.* from activity_searches s join users u ON s.user_id = u.id where u.team_id = 882;\nselect * from nudges n where n.activity_search_id\n\nselect * from teams where created_at > '2026-03-09';\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 1065; # 1065\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 3617;\n\nselect * from users where team_id = 1 and name like '%Lukas%'; # 7160\n\nSELECT * FROM teams WHERE id = 575;\nselect * from opportunities where team_id = 575;\nSELECT * FROM teams WHERE name LIKE '%Integrum ESG%'; # 1126, 1065,\nselect * from opportunities where team_id = 1126;\nSELECT * FROM teams WHERE name LIKE '%Base%'; # 1125, 1063,\nselect * from opportunities where team_id = 1125;\nselect * from contacts c\nwhere c.team_id = 882;\n\nSELECT * FROM activities WHERE id = 76822967;\nSELECT * FROM crm_profiles WHERE user_id = 15440;\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 555;\nSELECT * FROM crm_configurations WHERE id = 555;\nSELECT * FROM users WHERE id = 15440; # team. 581, gr. 15440, pl. 3911, act. field 162182\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 581 and sa.provider = 'salesforce';\n\nSELECT * FROM automated_report_results order by id desc;\n\nselect * from features;\nselect * from team_features where feature_id = 40;\n\nselect * from teams where id = 556;\n\nselect * from automated_reports;\nwhere id = 54; # 4fdd41f6-dcf0-30d0-b339-7345381b6044 , [\"pdf\",\"podcast\"]\nSELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;\nselect * from automated_report_results order by id desc;\nSELECT * FROM automated_report_results WHERE id = 1919;\n\nselect * from automated_report_results WHERE report_id = 54;\n\nselect * from opportunities where id = 7594349;\n\nSELECT * FROM teams WHERE name LIKE '%Les%'; # 711, 692, 16067 - jiminnyintegration@lesmills.com\nselect * from playbooks where team_id = 711; # event 226147\nSELECT * FROM playbook_categories WHERE playbook_id = 5515;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 692 and object_type = 'event';\nSELECT * FROM crm_fields WHERE id = 226147;\nSELECT * FROM crm_field_values WHERE crm_field_id = 226147;\n\nSELECT * FROM crm_configurations WHERE id = 692;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 711 and sa.provider = 'salesforce';\n\nSELECT * FROM crm_profiles cp JOIN users u on u.id = cp.user_id WHERE u.team_id = 711;\n\nselect * from leads;\n\nselect * from calendars;\n\nSELECT\n t.id AS team_id,\n t.name,\n LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1)) AS calendar_domain\nFROM teams t\nJOIN users u ON u.team_id = t.id\nJOIN calendars c ON c.user_id = u.id AND c.status = 'active' AND c.calendar_provider_id LIKE '%@%'\nLEFT JOIN team_domains td\n ON td.team_id = t.id\n AND td.deleted_at IS NULL\n AND td.domain = LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1))\nGROUP BY t.id, t.name, calendar_domain\nORDER BY t.name, calendar_domain;\n\nselect * from users u join calendars c on c.user_id = u.id\nwhere u.team_id = 882;\n\n\nselect * from activities where id = 74049485; # team 563 crm 537\nselect * from activities where id = 73272382; # team 563 crm 537\nselect * from activities where id = 64400389; # team 563 crm 537\nselect * from activities where id = 58081273; # team 563 crm 537\nselect * from activities where id = 54520297; # team 563 crm 537\nselect * from participants where activity_id = 58081273;\n\nselect * from activities where crm_configuration_id = 537 and provider = 'aircall'\nand account_id = 19003658 order by updated_at desc;\n\nselect * from contacts where crm_configuration_id = 537 and id = 35957759;\nselect * from accounts where crm_configuration_id = 537 and id = 19003658;\n\nselect * from automated_report_results where id = 1976;\nselect * from automated_reports where id = 583;\nselect * from activity_searches where id = 87714;\nselect * from activity_search_filters where activity_search_id = 87714;\n\nSELECT * FROM activities WHERE uuid_to_bin('8827f672-202d-4162-9d04-73ff5f0566a9') = uuid\nor uuid_to_bin('47842446-af51-4bcb-854f-cc6560290101') = uuid;","depth":4,"on_screen":true,"value":"SELECT * FROM teams WHERE name LIKE '%litify%'; # 1069, 994, 24993\nSELECT * FROM users WHERE id = 25061;\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 994;\nSELECT * FROM crm_profiles WHERE user_id = 25061;\n\nselect * from crm_configurations where id = 834;\nSELECT * FROM teams WHERE id = 882;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 882 and sa.provider = 'hubspot';\n\nSELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal\nSELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 933 and sa.provider = 'hubspot';\n\nSELECT * FROM crm_configurations WHERE provider = 'hubspot' and crm_provider_id = 7270388;\n\nSELECT * FROM contacts where crm_configuration_id = 834;\nSELECT * FROM opportunities WHERE team_id = 933\n# AND crm_provider_id IN ('20131586060','46017317898','52543911090','53451356564','54101251892','54323768459');\nAND id IN (8482561,18352941,19042734,19232139,19445140,19472541);\nSELECT * FROM opportunity_contacts\nWHERE opportunity_id IN (8482561,18352941,19042734,19232139,19445140,19472541);\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 485; #\nSELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 933 and sa.provider = 'hubspot';\n\nselect crm.provider, l.* from leads l join crm_configurations crm on l.crm_configuration_id = crm.id\nwhere crm.provider NOT IN ('salesforce', 'integration-app', 'bullhorn', 'copper')\n# and l.converted_at IS NOT NULL\n;\n\n# ********************************************************************\nSELECT * FROM activities a WHERE type IN ('email-inbound', 'email-outbound')\nand opportunity_id IS NULL\norder by id desc;\n\nSELECT * FROM teams WHERE id = 604; # 598\nSELECT * FROM activities WHERE id = 74410828; # chelseaw@allvoices.co\nSELECT * FROM accounts WHERE id = 20068382;\nSELECT * FROM accounts WHERE id = 35186038;\n\nSELECT * FROM contacts WHERE team_id = 852 and updated_at > '2026-01-23 12:30:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 559 and sa.provider = 'hubspot';\n\nSELECT * FROM activities WHERE uuid_to_bin('cb6342b6-a183-401c-b0af-ede92b2ae763') = uuid;\nselect * from sidekick_settings where team_id = 781;\n\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 26651871; # Teya\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 7562435;\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8420347; # opflit 2100\n\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 711;\nSELECT * FROM activities where crm_configuration_id = 711 and crm_provider_id IS NULL\nand is_internal = 0 and status = 'completed'\norder by id desc;\n\nSELECT * FROM crm_layout_entities\nWHERE crm_layout_id IN (2352, 2353);\n;\n\nSELECT * FROM crm_configurations where provider = 'hubspot' and id = 530;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 556 and sa.provider = 'hubspot';\n\nSELECT * FROM activities WHERE uuid_to_bin('c6ca4b22-7738-4563-a95d-b8a9598924ae') = uuid;\nSELECT * FROM activities WHERE uuid_to_bin('442abb2b-28bd-4be8-9c25-19e9bf02766d') = uuid;\nselect * from contacts\nwhere crm_configuration_id = 530\nand crm_provider_id = 872252;\n\nselect * from activities where crm_configuration_id = 530\nand user_id = 14343 and type like '%softphone%'\nand created_at between '2026-01-28 15:00:00' and '2026-01-28 15:10:00';\n\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 25666868; # Teya\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8646335; # Teya\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id IN (5933397);\n\n\nSELECT t.name, t.id, t.owner_id, c.id, c.provider, c.crm_base_url FROM teams t\nJOIN crm_configurations c ON t.id = c.team_id\nWHERE t.status = 'active';\n\nSELECT * FROM teams where id = 1091;\nSELECT * FROM crm_configurations where team_id = 1091;\nSELECT * FROM activity_providers where team_id = 1091;\nSELECT * FROM activities where crm_configuration_id = 1024 and type IN ('softphone', 'softphone-outbound')\nand provider NOT IN ('hubspot', 'aircall')\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by id desc;\n\n\nSELECT * FROM teams WHERE name LIKE '%Leadventure%';\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1091 and sa.provider = 'salesforce';\n\nSELECT * FROM teams WHERE name LIKE '%Wilson%'; # 862, 812\nSELECT * FROM teams where id = 862;\nSELECT * FROM crm_configurations where team_id = 862;\nSELECT * FROM activity_providers where team_id = 862;\nSELECT * FROM activities where crm_configuration_id = 812 and type IN ('softphone', 'softphone-outbound')\nand provider NOT IN ('hubspot', 'aircall')\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by id desc;\n\n\nSELECT t.id, crm.id, crm.provider, ap.* FROM teams t\njoin crm_configurations crm on t.id = crm.team_id\njoin activity_providers ap on t.id = ap.team_id\nwhere t.status = 'active' and ap.is_enabled = 1\nand crm.provider = 'hubspot'\nand ap.provider NOT IN ('hubspot', 'aircall', 'uploader', 'gong', 'twilio', 'zoom-bot', 'google-meet', 'ms-teams',\n 'outreach', 'close', 'ringcentral', 'dialpad', 'zoom-phone');\n\nSELECT * FROM teams where id = 1068;\nSELECT * FROM crm_configurations where team_id = 1068;\nSELECT * FROM activity_providers where team_id = 1068;\n\nSELECT * FROM activities a\nwhere crm_configuration_id = 993 and type IN ('softphone', 'softphone-outbound')\nand a.provider NOT IN ('hubspot', 'uploader', 'gong', 'twilio', 'google-meet', 'ms-teams','close'\n )\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by a.id desc;\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1068 and sa.provider = 'hubspot';\n\n# ********************************************************************\n# ********************************************************************\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal , portalId: 6017093\nSELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-06 00:00:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 933 and sa.provider = 'hubspot';\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 834; # 882 - AnyVan , portalId: 5468262\nSELECT * FROM contacts WHERE crm_configuration_id = 834 and updated_at > '2026-03-30 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE crm_configuration_id = 834 and updated_at > '2026-03-04 08:00:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 882 and sa.provider = 'hubspot';\nselect * from crm_layouts where crm_configuration_id = 834;\nselect * from crm_layout_entities where crm_layout_id = 2780;\nselect * from crm_fields where id IN (321153,321192,321193,321194);\n\nSELECT * FROM opportunities WHERE crm_configuration_id = 834 and id = 10993426;\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 988; # 1057 - Teya (543ce4f4-168c-4571-91ea-5b35c253f06f) , portalId: 26651871\nSELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1057 and sa.provider = 'hubspot';\n\nSELECT * FROM crm_configurations where id = 533; # 559 - Connectd , portalId: 6710988\nSELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 801; # 852 - Rise Vision , portalId: 2700250\nSELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-04 00:00:00' order by updated_at desc; # 6th last\n\nSELECT * FROM crm_configurations where id = 962; # 1034 - evergrowth.io , portalId: 143180990\nSELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 1037; # 1102 - Jibble , portalId: 6649755\nSELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 8\n\nSELECT * FROM crm_configurations where id = 1015; # 1049 - Travefy , portalId: 48904401\nSELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 20\n\nSELECT * FROM crm_configurations where id = 64; # 70 - SalaryFinance , portalId: 3404115\nSELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 6th last\n\nSELECT * FROM crm_configurations where id = 802; # 853 - Street Group , portalId: 7658438\nSELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 10\n\nSELECT * FROM crm_configurations where id = 872; # 921 - In Professional Development , portalId: 9238273\nSELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 2\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 550; # 576 - SeedLegals , portalId: 3028661\nSELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 989; # 1058 - rtaoutdoor.com , portalId: 22371204\nSELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 896; # 946 - Mintago , portalId: 6621281\nSELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 617; # 641 - PCS , portalId: 5244937\nSELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-05 14:00:00' order by updated_at desc; # 7th\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 649; # 670 - Eventeny , portalId: 4492849\nSELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; #\n\nSELECT * FROM crm_configurations where id = 48; # 51 - CleanCloud , portalId: 4373137\nSELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-03-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-02-09 08:00:00' order by updated_at desc;\nselect * from users where team_id = 51; # 7783\nSELECT * FROM groups WHERE uuid_to_bin('8a8d2cb6-8b55-4fa3-8b5c-5f0e3d8de59a') = uuid; # 1130\nselect * from activity_searches where user_id = 7783;\nselect * from activity_search_filters where activity_search_id IN (32291, 32292);\n\nSELECT asf.activity_search_id, asf.id, asf.value\nFROM activity_search_filters asf\nWHERE asf.filter = 'group_id'\nAND asf.value IN (\n SELECT CONCAT(\n HEX(SUBSTR(uuid, 5, 4)), '-',\n HEX(SUBSTR(uuid, 3, 2)), '-',\n HEX(SUBSTR(uuid, 1, 2)), '-',\n HEX(SUBSTR(uuid, 9, 2)), '-',\n HEX(SUBSTR(uuid, 11))\n )\n FROM groups\n WHERE deleted_at IS NOT NULL\n);\n\nSELECT * FROM crm_configurations where id = 272; # 290 - Bonham & Brook , portalId: 5705856\nSELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-05 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; # 6th\n# ********************************************************************\nSELECT * FROM crm_configurations where provider = 'hubspot';\nSELECT * FROM crm_configurations where id = 1056; # 1119 - Chromatic , portalId: 45602133\nSELECT * FROM opportunities WHERE team_id = 1119 and remotely_created_at > '2026-02-01 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1119 and updated_at > '2026-02-09 09:00:00' order by updated_at desc; # null\n# ********************************************************************\n\nselect * from contacts where crm_provider_id = '003Uu00000ojD4NIAU';\nselect\n cp.*\n# DISTINCT t.id\n# cp.id, cp.user_id, t.id, cp.crm_configuration_id, cp.contact_fields\nFROM crm_profiles cp\nJOIN crm_configurations crm on crm.id = cp.crm_configuration_id\nJOIN users u on u.id = cp.user_id\nJOIN teams t ON t.id = crm.team_id\nWHERE crm.provider = 'salesforce' and t.status = 'active'\n and cp.archived_at IS NULL and u.deleted_at IS NULL\n and t.id NOT IN (1093)\n and t.id = 2\n and cp.contact_fields IS NULL;\n# and c.crm_provider_id = '003Uu00000ojD4NIAU';\n\nSELECT * FROM users WHERE id = 26484;\nSELECT * FROM crm_profiles WHERE user_id = 26484;\nSELECT * FROM social_accounts WHERE sociable_id = 26484;\nSELECT * FROM crm_configurations where provider = 'salesforce';\nselect * from users where id IN (10022, 10403);\nselect * from users where team_id IN (526);\nselect * from teams where id IN (526, 532);\nselect * from crm_configurations where id IN (500, 516);\nselect * from crm_profiles where crm_configuration_id IN (500, 516) and user_id IN (10022, 10403);\nselect * from contacts where crm_configuration_id IN (500, 516) and crm_provider_id = '003Uu00000ojD4NIAU';\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 526 and sa.provider = 'salesforce';\nselect * from team_settings where team_id IN (526, 532);\n\nselect * from users where id IN (22824);\nselect * from crm_profiles where crm_configuration_id IN (1026);\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1093 and sa.provider = 'salesforce';\n\nselect * from teams where id = 1099;\nselect * from users where id = 29643\n\nselect * from activity_processing_states;\n\nSELECT * FROM teams where name LIKE '%Fare%'; # 233\nSELECT * FROM opportunities where crm_configuration_id = 215\n# and crm_provider_id = 'oppo_ogESZf2P50nDrd1nGPvKDXeA6sSaTN5v51Lp4ayVzKR'\n;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1088 and sa.provider = 'hubspot';\n\nSELECT * FROM teams order by updated_at DESC\nSELECT * FROM crm_configurations WHERE id = 1019; # SimpleConsign 1088 - no social account\n\nselect * from crm_configurations where provider = 'pipedrive';\n\nselect * from teams where id = 957;\nselect * from crm_configurations where id = 957;\n\nSELECT * FROM teams WHERE name LIKE '%Prolific%'; # 544, 518, 10743\nSELECT * FROM opportunities where crm_configuration_id = 518 order by id desc;\n\nselect * from users where team_id = 1; # 26726 - Gabriela Dureva\nSELECT * FROM opportunities where user_id = 26726; # 16834447 - Prolific\nselect * from activities where user_id = 26726 order by id desc;\nselect * from contacts where crm_configuration_id = 1\nand email IN ('charlotte.ward@prolific.com', 'frankie.bryant@prolific.com'); # 2094416, 2093620\nSELECT * FROM contacts WHERE id = 6284931;\n\nSELECT p.* FROM activities a JOIN participants p ON a.id = p.activity_id\nWHERE a.user_id = 26726 and p.lead_id IN (2094416, 2093620) and a.created_at > '2026-01-01 00:00:00' order by p.email;\n\nselect * from activities where id IN (75509259,75509261,75509261,75511034,75026464,75517602,75517605);\nselect * from crm_configurations where id = 1;\n\n43801692-1aeb-32ce-acba-5b80a479701a\n44c3c9cf-6f5e-75f3-8179-bc9f75dd2b1b\n405975c0-b3d0-7aaa-821f-09d59cae6dd1\n4caf848d-4bed-2299-b248-7788d41f9fca\n49bedc3f-f196-eef3-89c3-dea6a3b4aa63\n43420989-a09d-b8f8-9806-c8bbf7a02aac\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1 and sa.provider = 'salesforce';\n\nSELECT * FROM activities WHERE id = 75461988;\n\nSELECT * FROM activities WHERE uuid_to_bin('d6c5052e-e972-49e9-8912-26f2f7d6c5f6') = uuid;\n\nselect * from contacts where id = 17900517;\n\nselect * from contact_roles cr join crm_configurations crm on cr.crm_configuration_id = crm.id\nwhere crm.provider != 'salesforce';\n\nselect * from users where id = 21047;\nSELECT * FROM crm_configurations WHERE id = 892;\nSELECT * FROM teams WHERE id = 942;\nselect * from opportunities where team_id = 942 order by updated_at desc;\nselect * from contacts where team_id = 942 order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 942 and sa.provider = 'hubspot';\n\nSELECT * FROM opportunities where team_id = 1 and crm_provider_id IN ('006Pq00000NeH6XIAV', '006Pq000007z8kdIAA'); # 10697889, 6621430\nSELECT * FROM crm_configurations WHERE id = 1;\nSELECT * FROM teams WHERE crm_id = 1;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1 and sa.provider = 'salesforce';\n\nselect id, user_id, opportunity_fields from crm_profiles where crm_configuration_id = 1\nSELECT * FROM opportunities where team_id = 1 order by updated_at desc; # 10697889, 6621430\n\nselect * from teams where id = 852;\nselect * from groups where id = 2286;\nselect * from sidekick_settings where team_id = 852;\nselect * from default_activity_types where team_id = 852;\n\n\nSELECT cc.provider, cc.id, p.id, u.*\nFROM users u\nLEFT JOIN crm_profiles p ON u.id = p.user_id AND p.id IS NULL -- no profile\nINNER JOIN teams t ON u.team_id = t.id AND t.status = 'active' -- team is active\nINNER JOIN crm_configurations cc ON t.crm_id = cc.id\nWHERE u.status = 1 AND u.deleted_at IS NULL\nAND u.crm_required = 1\nAND u.team_id = 1\nORDER BY u.team_id;\n\nSELECT * FROM crm_profiles cp where cp.crm_configuration_id = 1 and cp.user_id IN (\n18481\n );\n\nSELECT cc.provider, cc.id, p.id, u.*\nFROM users u\nLEFT JOIN crm_profiles p ON u.id = p.user_id\nINNER JOIN teams t ON u.team_id = t.id AND t.status = 'active'\nINNER JOIN crm_configurations cc ON t.crm_id = cc.id\nWHERE u.status = 1\n AND u.deleted_at IS NULL\n AND u.crm_required = 1\n# AND u.team_id = 1\n AND p.id IS NULL -- Move this condition to WHERE clause\nORDER BY u.team_id;\n\nSELECT * FROM opportunities WHERE id = 20002609;\nselect * from teams where id = 1122; # Velatir, 29953 - christian@velatir.com\nselect * from crm_configurations where id = 1060;\nselect * from crm_layouts where crm_configuration_id = 1060;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 3596;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1122 and sa.provider = 'hubspot';\nselect * from opportunities where team_id = 1122 order by updated_at desc;\n\nselect * from crm_field_data where object_type = 'contact';\n\nSELECT * FROM activities WHERE uuid_to_bin('374fc8ed-3315-4c9f-9b25-318b7fd2928f') = uuid; # 76584262\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 248 and sa.provider = 'salesforce';\n\nSELECT * FROM crm_profiles where user_id = 24115; # 005QF000002CswMYAS\nSELECT * FROM users where id = 24115;\nSELECT * FROM accounts where id = 4002896;\nSELECT * FROM teams WHERE name LIKE '%adswerve%';\nSELECT * FROM opportunities where crm_configuration_id = 230 AND crm_provider_id IN (\"0069N000003GIQ9QAO\",\"0061r000019yGP9AAM\",\"0066900001S2KWlAAN\",\"0066900001TDpj2AAD\",\"0066900001b8uEwAAI\",\"0069N000001rQi0QAE\",\"006QF00000KD40mYAD\",\"006QF00000LzpRJYAZ\",\"0069N000002uomtQAA\",\"0069N000002xlMLQAY\",\"0066900001NV6ubAAD\",\"0061r00001HJp45AAD\",\"006QF00000uTlUoYAK\",\"006QF00000v0bZqYAI\");\nSELECT * FROM opportunities WHERE crm_configuration_id = 230 AND crm_provider_id = '0069N000003GIQ9QAO'; # 6272203\n\nSELECT u.id, u.email, ac.name, a.* FROM activities a\nJOIN users u ON a.user_id = u.id\nJOIN accounts ac ON a.account_id = ac.id\nWHERE\nuuid_to_bin('e3269598-b562-44fb-b5e9-9d2694dc63e0') = a.uuid or\nuuid_to_bin('66ddc3ab-4e15-45aa-af0c-248c1eece593') = a.uuid or\nuuid_to_bin('826bd328-e1cc-4213-b8d8-572454cacc07') = a.uuid;\n\nselect * from users where id = 5825;\nSELECT * FROM activities WHERE uuid_to_bin('e56aa2e8-231a-421b-ab1f-cb38ed2bf573') = uuid;\n\nselect * from activities where uuid_to_bin('91e13b2f-2d1b-45f8-b1fd-1141b6563782') = uuid;\n19594, 862\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 862 and sa.provider = 'salesforce';\n\nselect * from automated_reports where id = 36;\nselect ar.frequency, r.*, ar.* from automated_report_results r\njoin automated_reports ar on r.report_id = ar.id\nwhere ar.frequency != 'one_off';\n\nselect s.* from activity_searches s join users u ON s.user_id = u.id where u.team_id = 882;\nselect * from nudges n where n.activity_search_id\n\nselect * from teams where created_at > '2026-03-09';\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 1065; # 1065\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 3617;\n\nselect * from users where team_id = 1 and name like '%Lukas%'; # 7160\n\nSELECT * FROM teams WHERE id = 575;\nselect * from opportunities where team_id = 575;\nSELECT * FROM teams WHERE name LIKE '%Integrum ESG%'; # 1126, 1065,\nselect * from opportunities where team_id = 1126;\nSELECT * FROM teams WHERE name LIKE '%Base%'; # 1125, 1063,\nselect * from opportunities where team_id = 1125;\nselect * from contacts c\nwhere c.team_id = 882;\n\nSELECT * FROM activities WHERE id = 76822967;\nSELECT * FROM crm_profiles WHERE user_id = 15440;\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 555;\nSELECT * FROM crm_configurations WHERE id = 555;\nSELECT * FROM users WHERE id = 15440; # team. 581, gr. 15440, pl. 3911, act. field 162182\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 581 and sa.provider = 'salesforce';\n\nSELECT * FROM automated_report_results order by id desc;\n\nselect * from features;\nselect * from team_features where feature_id = 40;\n\nselect * from teams where id = 556;\n\nselect * from automated_reports;\nwhere id = 54; # 4fdd41f6-dcf0-30d0-b339-7345381b6044 , [\"pdf\",\"podcast\"]\nSELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;\nselect * from automated_report_results order by id desc;\nSELECT * FROM automated_report_results WHERE id = 1919;\n\nselect * from automated_report_results WHERE report_id = 54;\n\nselect * from opportunities where id = 7594349;\n\nSELECT * FROM teams WHERE name LIKE '%Les%'; # 711, 692, 16067 - jiminnyintegration@lesmills.com\nselect * from playbooks where team_id = 711; # event 226147\nSELECT * FROM playbook_categories WHERE playbook_id = 5515;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 692 and object_type = 'event';\nSELECT * FROM crm_fields WHERE id = 226147;\nSELECT * FROM crm_field_values WHERE crm_field_id = 226147;\n\nSELECT * FROM crm_configurations WHERE id = 692;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 711 and sa.provider = 'salesforce';\n\nSELECT * FROM crm_profiles cp JOIN users u on u.id = cp.user_id WHERE u.team_id = 711;\n\nselect * from leads;\n\nselect * from calendars;\n\nSELECT\n t.id AS team_id,\n t.name,\n LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1)) AS calendar_domain\nFROM teams t\nJOIN users u ON u.team_id = t.id\nJOIN calendars c ON c.user_id = u.id AND c.status = 'active' AND c.calendar_provider_id LIKE '%@%'\nLEFT JOIN team_domains td\n ON td.team_id = t.id\n AND td.deleted_at IS NULL\n AND td.domain = LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1))\nGROUP BY t.id, t.name, calendar_domain\nORDER BY t.name, calendar_domain;\n\nselect * from users u join calendars c on c.user_id = u.id\nwhere u.team_id = 882;\n\n\nselect * from activities where id = 74049485; # team 563 crm 537\nselect * from activities where id = 73272382; # team 563 crm 537\nselect * from activities where id = 64400389; # team 563 crm 537\nselect * from activities where id = 58081273; # team 563 crm 537\nselect * from activities where id = 54520297; # team 563 crm 537\nselect * from participants where activity_id = 58081273;\n\nselect * from activities where crm_configuration_id = 537 and provider = 'aircall'\nand account_id = 19003658 order by updated_at desc;\n\nselect * from contacts where crm_configuration_id = 537 and id = 35957759;\nselect * from accounts where crm_configuration_id = 537 and id = 19003658;\n\nselect * from automated_report_results where id = 1976;\nselect * from automated_reports where id = 583;\nselect * from activity_searches where id = 87714;\nselect * from activity_search_filters where activity_search_id = 87714;\n\nSELECT * FROM activities WHERE uuid_to_bin('8827f672-202d-4162-9d04-73ff5f0566a9') = uuid\nor uuid_to_bin('47842446-af51-4bcb-854f-cc6560290101') = uuid;","role_description":"text entry area","is_enabled":true,"is_focused":true,"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":"4","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\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Console\\Commands\\Dev;\n\nuse Jiminny\\Console\\Commands\\Command;\nuse Jiminny\\Contracts\\Http\\RateLimited;\nuse Jiminny\\Models\\Activity\\Provider;\nuse Jiminny\\Models\\Crm\\Configuration;\n\nclass AddRateLimitCommand extends Command\n{\n private const TYPE_ACTIVITY_PROVIDER = Provider::class;\n private const TYPE_CRM_CONFIGURATION = Configuration::class;\n private const RATE_LIMITED_TYPES = [self::TYPE_ACTIVITY_PROVIDER, self::TYPE_CRM_CONFIGURATION];\n\n protected $signature = 'jiminny:add-rate-limit';\n\n public function handle(): void\n {\n $type = $this->choice('Choose type', self::RATE_LIMITED_TYPES);\n $id = $this->ask(sprintf('Enter an ID of the %s', $type));\n $quota = (int) $this->ask('Enter number of requests');\n $window = (int) $this->ask('Enter request window in seconds');\n\n $rateLimited = (new $type())::find($id);\n\n if (! $rateLimited instanceof RateLimited) {\n $this->error('Model not found');\n\n return;\n }\n\n $rateLimited->rateLimits()->updateOrCreate([\n 'limited_id' => $id,\n 'limited_type' => $type,\n 'quota' => $quota,\n 'window' => $window,\n ]);\n\n $this->info('Done');\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Console\\Commands\\Dev;\n\nuse Jiminny\\Console\\Commands\\Command;\nuse Jiminny\\Contracts\\Http\\RateLimited;\nuse Jiminny\\Models\\Activity\\Provider;\nuse Jiminny\\Models\\Crm\\Configuration;\n\nclass AddRateLimitCommand extends Command\n{\n private const TYPE_ACTIVITY_PROVIDER = Provider::class;\n private const TYPE_CRM_CONFIGURATION = Configuration::class;\n private const RATE_LIMITED_TYPES = [self::TYPE_ACTIVITY_PROVIDER, self::TYPE_CRM_CONFIGURATION];\n\n protected $signature = 'jiminny:add-rate-limit';\n\n public function handle(): void\n {\n $type = $this->choice('Choose type', self::RATE_LIMITED_TYPES);\n $id = $this->ask(sprintf('Enter an ID of the %s', $type));\n $quota = (int) $this->ask('Enter number of requests');\n $window = (int) $this->ask('Enter request window in seconds');\n\n $rateLimited = (new $type())::find($id);\n\n if (! $rateLimited instanceof RateLimited) {\n $this->error('Model not found');\n\n return;\n }\n\n $rateLimited->rateLimits()->updateOrCreate([\n 'limited_id' => $id,\n 'limited_type' => $type,\n 'quota' => $quota,\n 'window' => $window,\n ]);\n\n $this->info('Done');\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"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},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Acl, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activity, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dtos, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Events, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AWS, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Cache, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Country, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Database, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Datadog, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DateTime, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encoding, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encryption, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ES, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Faker, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FFMpeg, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FileSystem, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gecko, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gong, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GuzzleHttp, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"KeyPoints, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Kiosk, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LanguageDetection, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LiveFeed, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Locks, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Math, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MediaPipeline, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MeetingBot, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MobileSettings, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Model, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Notification, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Nudge, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParagraphBreaker, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParticipantSpeech, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PartitionedCookie, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackPage, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playlist, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Prophet, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProphetAi, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProsperWorks, folder","depth":9,"on_screen":false,"role_description":"text"}]...
|
-8095906125804275933
|
1065678670634825285
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Code changed:
Hide
Sync Changes
Hide This Notification
37
1
35
63
Previous Highlighted Error
Next Highlighted Error
SELECT * FROM teams WHERE name LIKE '%litify%'; # 1069, 994, 24993
SELECT * FROM users WHERE id = 25061;
SELECT * FROM crm_profiles WHERE crm_configuration_id = 994;
SELECT * FROM crm_profiles WHERE user_id = 25061;
select * from crm_configurations where id = 834;
SELECT * FROM teams WHERE id = 882;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 882 and sa.provider = 'hubspot';
SELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal
SELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 933 and sa.provider = 'hubspot';
SELECT * FROM crm_configurations WHERE provider = 'hubspot' and crm_provider_id = 7270388;
SELECT * FROM contacts where crm_configuration_id = 834;
SELECT * FROM opportunities WHERE team_id = 933
# AND crm_provider_id IN ('20131586060','46017317898','52543911090','53451356564','54101251892','54323768459');
AND id IN (8482561,18352941,19042734,19232139,19445140,19472541);
SELECT * FROM opportunity_contacts
WHERE opportunity_id IN (8482561,18352941,19042734,19232139,19445140,19472541);
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 485; #
SELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 933 and sa.provider = 'hubspot';
select crm.provider, l.* from leads l join crm_configurations crm on l.crm_configuration_id = crm.id
where crm.provider NOT IN ('salesforce', 'integration-app', 'bullhorn', 'copper')
# and l.converted_at IS NOT NULL
;
# [PASSWORD_DOTS]
SELECT * FROM activities a WHERE type IN ('email-inbound', 'email-outbound')
and opportunity_id IS NULL
order by id desc;
SELECT * FROM teams WHERE id = 604; # 598
SELECT * FROM activities WHERE id = 74410828; # [EMAIL]
SELECT * FROM accounts WHERE id = 20068382;
SELECT * FROM accounts WHERE id = 35186038;
SELECT * FROM contacts WHERE team_id = 852 and updated_at > '2026-01-23 12:30:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 559 and sa.provider = 'hubspot';
SELECT * FROM activities WHERE uuid_to_bin('cb6342b6-a183-401c-b0af-ede92b2ae763') = uuid;
select * from sidekick_settings where team_id = 781;
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 26651871; # Teya
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 7562435;
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8420347; # opflit 2100
SELECT * FROM crm_layouts WHERE crm_configuration_id = 711;
SELECT * FROM activities where crm_configuration_id = 711 and crm_provider_id IS NULL
and is_internal = 0 and status = 'completed'
order by id desc;
SELECT * FROM crm_layout_entities
WHERE crm_layout_id IN (2352, 2353);
;
SELECT * FROM crm_configurations where provider = 'hubspot' and id = 530;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 556 and sa.provider = 'hubspot';
SELECT * FROM activities WHERE uuid_to_bin('c6ca4b22-7738-4563-a95d-b8a9598924ae') = uuid;
SELECT * FROM activities WHERE uuid_to_bin('442abb2b-28bd-4be8-9c25-19e9bf02766d') = uuid;
select * from contacts
where crm_configuration_id = 530
and crm_provider_id = 872252;
select * from activities where crm_configuration_id = 530
and user_id = 14343 and type like '%softphone%'
and created_at between '2026-01-28 15:00:00' and '2026-01-28 15:10:00';
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 25666868; # Teya
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8646335; # Teya
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id IN (5933397);
SELECT t.name, t.id, t.owner_id, c.id, c.provider, c.crm_base_url FROM teams t
JOIN crm_configurations c ON t.id = c.team_id
WHERE t.status = 'active';
SELECT * FROM teams where id = 1091;
SELECT * FROM crm_configurations where team_id = 1091;
SELECT * FROM activity_providers where team_id = 1091;
SELECT * FROM activities where crm_configuration_id = 1024 and type IN ('softphone', 'softphone-outbound')
and provider NOT IN ('hubspot', 'aircall')
# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'
order by id desc;
SELECT * FROM teams WHERE name LIKE '%Leadventure%';
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1091 and sa.provider = 'salesforce';
SELECT * FROM teams WHERE name LIKE '%Wilson%'; # 862, 812
SELECT * FROM teams where id = 862;
SELECT * FROM crm_configurations where team_id = 862;
SELECT * FROM activity_providers where team_id = 862;
SELECT * FROM activities where crm_configuration_id = 812 and type IN ('softphone', 'softphone-outbound')
and provider NOT IN ('hubspot', 'aircall')
# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'
order by id desc;
SELECT t.id, crm.id, crm.provider, ap.* FROM teams t
join crm_configurations crm on t.id = crm.team_id
join activity_providers ap on t.id = ap.team_id
where t.status = 'active' and ap.is_enabled = 1
and crm.provider = 'hubspot'
and ap.provider NOT IN ('hubspot', 'aircall', 'uploader', 'gong', 'twilio', 'zoom-bot', 'google-meet', 'ms-teams',
'outreach', 'close', 'ringcentral', 'dialpad', 'zoom-phone');
SELECT * FROM teams where id = 1068;
SELECT * FROM crm_configurations where team_id = 1068;
SELECT * FROM activity_providers where team_id = 1068;
SELECT * FROM activities a
where crm_configuration_id = 993 and type IN ('softphone', 'softphone-outbound')
and a.provider NOT IN ('hubspot', 'uploader', 'gong', 'twilio', 'google-meet', 'ms-teams','close'
)
# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'
order by a.id desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1068 and sa.provider = 'hubspot';
# [PASSWORD_DOTS]
# [PASSWORD_DOTS]
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal , portalId: 6017093
SELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-06 00:00:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 933 and sa.provider = 'hubspot';
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 834; # 882 - AnyVan , portalId: 5468262
SELECT * FROM contacts WHERE crm_configuration_id = 834 and updated_at > '2026-03-30 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE crm_configuration_id = 834 and updated_at > '2026-03-04 08:00:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 882 and sa.provider = 'hubspot';
select * from crm_layouts where crm_configuration_id = 834;
select * from crm_layout_entities where crm_layout_id = 2780;
select * from crm_fields where id IN (321153,321192,321193,321194);
SELECT * FROM opportunities WHERE crm_configuration_id = 834 and id = 10993426;
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 988; # 1057 - Teya (543ce4f4-168c-4571-91ea-5b35c253f06f) , portalId: 26651871
SELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1057 and sa.provider = 'hubspot';
SELECT * FROM crm_configurations where id = 533; # 559 - Connectd , portalId: 6710988
SELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 801; # 852 - Rise Vision , portalId: 2700250
SELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-04 00:00:00' order by updated_at desc; # 6th last
SELECT * FROM crm_configurations where id = 962; # 1034 - evergrowth.io , portalId: 143180990
SELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 1037; # 1102 - Jibble , portalId: 6649755
SELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 8
SELECT * FROM crm_configurations where id = 1015; # 1049 - Travefy , portalId: 48904401
SELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 20
SELECT * FROM crm_configurations where id = 64; # 70 - SalaryFinance , portalId: 3404115
SELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 6th last
SELECT * FROM crm_configurations where id = 802; # 853 - Street Group , portalId: 7658438
SELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 10
SELECT * FROM crm_configurations where id = 872; # 921 - In Professional Development , portalId: 9238273
SELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 2
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 550; # 576 - SeedLegals , portalId: 3028661
SELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 989; # 1058 - rtaoutdoor.com , portalId: 22371204
SELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 896; # 946 - Mintago , portalId: 6621281
SELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 617; # 641 - PCS , portalId: 5244937
SELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-05 14:00:00' order by updated_at desc; # 7th
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 649; # 670 - Eventeny , portalId: 4492849
SELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; #
SELECT * FROM crm_configurations where id = 48; # 51 - CleanCloud , portalId: 4373137
SELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-03-04 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-02-09 08:00:00' order by updated_at desc;
select * from users where team_id = 51; # 7783
SELECT * FROM groups WHERE uuid_to_bin('8a8d2cb6-8b55-4fa3-8b5c-5f0e3d8de59a') = uuid; # 1130
select * from activity_searches where user_id = 7783;
select * from activity_search_filters where activity_search_id IN (32291, 32292);
SELECT asf.activity_search_id, asf.id, asf.value
FROM activity_search_filters asf
WHERE asf.filter = 'group_id'
AND asf.value IN (
SELECT CONCAT(
HEX(SUBSTR(uuid, 5, 4)), '-',
HEX(SUBSTR(uuid, 3, 2)), '-',
HEX(SUBSTR(uuid, 1, 2)), '-',
HEX(SUBSTR(uuid, 9, 2)), '-',
HEX(SUBSTR(uuid, 11))
)
FROM groups
WHERE deleted_at IS NOT NULL
);
SELECT * FROM crm_configurations where id = 272; # 290 - Bonham & Brook , portalId: 5705856
SELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-05 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; # 6th
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where provider = 'hubspot';
SELECT * FROM crm_configurations where id = 1056; # 1119 - Chromatic , portalId: 45602133
SELECT * FROM opportunities WHERE team_id = 1119 and remotely_created_at > '2026-02-01 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1119 and updated_at > '2026-02-09 09:00:00' order by updated_at desc; # null
# [PASSWORD_DOTS]
select * from contacts where crm_provider_id = '003Uu00000ojD4NIAU';
select
cp.*
# DISTINCT t.id
# cp.id, cp.user_id, t.id, cp.crm_configuration_id, cp.contact_fields
FROM crm_profiles cp
JOIN crm_configurations crm on crm.id = cp.crm_configuration_id
JOIN users u on u.id = cp.user_id
JOIN teams t ON t.id = crm.team_id
WHERE crm.provider = 'salesforce' and t.status = 'active'
and cp.archived_at IS NULL and u.deleted_at IS NULL
and t.id NOT IN (1093)
and t.id = 2
and cp.contact_fields IS NULL;
# and c.crm_provider_id = '003Uu00000ojD4NIAU';
SELECT * FROM users WHERE id = 26484;
SELECT * FROM crm_profiles WHERE user_id = 26484;
SELECT * FROM social_accounts WHERE sociable_id = 26484;
SELECT * FROM crm_configurations where provider = 'salesforce';
select * from users where id IN (10022, 10403);
select * from users where team_id IN (526);
select * from teams where id IN (526, 532);
select * from crm_configurations where id IN (500, 516);
select * from crm_profiles where crm_configuration_id IN (500, 516) and user_id IN (10022, 10403);
select * from contacts where crm_configuration_id IN (500, 516) and crm_provider_id = '003Uu00000ojD4NIAU';
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 526 and sa.provider = 'salesforce';
select * from team_settings where team_id IN (526, 532);
select * from users where id IN (22824);
select * from crm_profiles where crm_configuration_id IN (1026);
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1093 and sa.provider = 'salesforce';
select * from teams where id = 1099;
select * from users where id = 29643
select * from activity_processing_states;
SELECT * FROM teams where name LIKE '%Fare%'; # 233
SELECT * FROM opportunities where crm_configuration_id = 215
# and crm_provider_id = 'oppo_ogESZf2P50nDrd1nGPvKDXeA6sSaTN5v51Lp4ayVzKR'
;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1088 and sa.provider = 'hubspot';
SELECT * FROM teams order by updated_at DESC
SELECT * FROM crm_configurations WHERE id = 1019; # SimpleConsign 1088 - no social account
select * from crm_configurations where provider = 'pipedrive';
select * from teams where id = 957;
select * from crm_configurations where id = 957;
SELECT * FROM teams WHERE name LIKE '%Prolific%'; # 544, 518, 10743
SELECT * FROM opportunities where crm_configuration_id = 518 order by id desc;
select * from users where team_id = 1; # 26726 - Gabriela Dureva
SELECT * FROM opportunities where user_id = 26726; # 16834447 - Prolific
select * from activities where user_id = 26726 order by id desc;
select * from contacts where crm_configuration_id = 1
and email IN ('[EMAIL]', '[EMAIL]'); # 2094416, 2093620
SELECT * FROM contacts WHERE id = 6284931;
SELECT p.* FROM activities a JOIN participants p ON a.id = p.activity_id
WHERE a.user_id = 26726 and p.lead_id IN (2094416, 2093620) and a.created_at > '2026-01-01 00:00:00' order by p.email;
select * from activities where id IN (75509259,75509261,75509261,75511034,75026464,75517602,75517605);
select * from crm_configurations where id = 1;
43801692-1aeb-32ce-acba-5b80a479701a
44c3c9cf-6f5e-75f3-8179-bc9f75dd2b1b
405975c0-b3d0-7aaa-821f-09d59cae6dd1
4caf848d-4bed-2299-b248-7788d41f9fca
49bedc3f-f196-eef3-89c3-dea6a3b4aa63
43420989-a09d-b8f8-9806-c8bbf7a02aac
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1 and sa.provider = 'salesforce';
SELECT * FROM activities WHERE id = 75461988;
SELECT * FROM activities WHERE uuid_to_bin('d6c5052e-e972-49e9-8912-26f2f7d6c5f6') = uuid;
select * from contacts where id = 17900517;
select * from contact_roles cr join crm_configurations crm on cr.crm_configuration_id = crm.id
where crm.provider != 'salesforce';
select * from users where id = 21047;
SELECT * FROM crm_configurations WHERE id = 892;
SELECT * FROM teams WHERE id = 942;
select * from opportunities where team_id = 942 order by updated_at desc;
select * from contacts where team_id = 942 order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 942 and sa.provider = 'hubspot';
SELECT * FROM opportunities where team_id = 1 and crm_provider_id IN ('006Pq00000NeH6XIAV', '006Pq000007z8kdIAA'); # 10697889, 6621430
SELECT * FROM crm_configurations WHERE id = 1;
SELECT * FROM teams WHERE crm_id = 1;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1 and sa.provider = 'salesforce';
select id, user_id, opportunity_fields from crm_profiles where crm_configuration_id = 1
SELECT * FROM opportunities where team_id = 1 order by updated_at desc; # 10697889, 6621430
select * from teams where id = 852;
select * from groups where id = 2286;
select * from sidekick_settings where team_id = 852;
select * from default_activity_types where team_id = 852;
SELECT cc.provider, cc.id, p.id, u.*
FROM users u
LEFT JOIN crm_profiles p ON u.id = p.user_id AND p.id IS NULL -- no profile
INNER JOIN teams t ON u.team_id = t.id AND t.status = 'active' -- team is active
INNER JOIN crm_configurations cc ON t.crm_id = cc.id
WHERE u.status = 1 AND u.deleted_at IS NULL
AND u.crm_required = 1
AND u.team_id = 1
ORDER BY u.team_id;
SELECT * FROM crm_profiles cp where cp.crm_configuration_id = 1 and cp.user_id IN (
18481
);
SELECT cc.provider, cc.id, p.id, u.*
FROM users u
LEFT JOIN crm_profiles p ON u.id = p.user_id
INNER JOIN teams t ON u.team_id = t.id AND t.status = 'active'
INNER JOIN crm_configurations cc ON t.crm_id = cc.id
WHERE u.status = 1
AND u.deleted_at IS NULL
AND u.crm_required = 1
# AND u.team_id = 1
AND p.id IS NULL -- Move this condition to WHERE clause
ORDER BY u.team_id;
SELECT * FROM opportunities WHERE id = 20002609;
select * from teams where id = 1122; # Velatir, 29953 - [EMAIL]
select * from crm_configurations where id = 1060;
select * from crm_layouts where crm_configuration_id = 1060;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 3596;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1122 and sa.provider = 'hubspot';
select * from opportunities where team_id = 1122 order by updated_at desc;
select * from crm_field_data where object_type = 'contact';
SELECT * FROM activities WHERE uuid_to_bin('374fc8ed-3315-4c9f-9b25-318b7fd2928f') = uuid; # 76584262
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 248 and sa.provider = 'salesforce';
SELECT * FROM crm_profiles where user_id = 24115; # 005QF000002CswMYAS
SELECT * FROM users where id = 24115;
SELECT * FROM accounts where id = 4002896;
SELECT * FROM teams WHERE name LIKE '%adswerve%';
SELECT * FROM opportunities where crm_configuration_id = 230 AND crm_provider_id IN ("0069N000003GIQ9QAO","0061r000019yGP9AAM","0066900001S2KWlAAN","0066900001TDpj2AAD","0066900001b8uEwAAI","0069N000001rQi0QAE","006QF00000KD40mYAD","006QF00000LzpRJYAZ","0069N000002uomtQAA","0069N000002xlMLQAY","0066900001NV6ubAAD","0061r00001HJp45AAD","006QF00000uTlUoYAK","006QF00000v0bZqYAI");
SELECT * FROM opportunities WHERE crm_configuration_id = 230 AND crm_provider_id = '0069N000003GIQ9QAO'; # 6272203
SELECT u.id, u.email, ac.name, a.* FROM activities a
JOIN users u ON a.user_id = u.id
JOIN accounts ac ON a.account_id = ac.id
WHERE
uuid_to_bin('e3269598-b562-44fb-b5e9-9d2694dc63e0') = a.uuid or
uuid_to_bin('66ddc3ab-4e15-45aa-af0c-248c1eece593') = a.uuid or
uuid_to_bin('826bd328-e1cc-4213-b8d8-572454cacc07') = a.uuid;
select * from users where id = 5825;
SELECT * FROM activities WHERE uuid_to_bin('e56aa2e8-231a-421b-ab1f-cb38ed2bf573') = uuid;
select * from activities where uuid_to_bin('91e13b2f-2d1b-45f8-b1fd-1141b6563782') = uuid;
19594, 862
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 862 and sa.provider = 'salesforce';
select * from automated_reports where id = 36;
select ar.frequency, r.*, ar.* from automated_report_results r
join automated_reports ar on r.report_id = ar.id
where ar.frequency != 'one_off';
select s.* from activity_searches s join users u ON s.user_id = u.id where u.team_id = 882;
select * from nudges n where n.activity_search_id
select * from teams where created_at > '2026-03-09';
SELECT * FROM crm_layouts WHERE crm_configuration_id = 1065; # 1065
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 3617;
select * from users where team_id = 1 and name like '%Lukas%'; # 7160
SELECT * FROM teams WHERE id = 575;
select * from opportunities where team_id = 575;
SELECT * FROM teams WHERE name LIKE '%Integrum ESG%'; # 1126, 1065,
select * from opportunities where team_id = 1126;
SELECT * FROM teams WHERE name LIKE '%Base%'; # 1125, 1063,
select * from opportunities where team_id = 1125;
select * from contacts c
where c.team_id = 882;
SELECT * FROM activities WHERE id = 76822967;
SELECT * FROM crm_profiles WHERE user_id = 15440;
SELECT * FROM crm_profiles WHERE crm_configuration_id = 555;
SELECT * FROM crm_configurations WHERE id = 555;
SELECT * FROM users WHERE id = 15440; # team. 581, gr. 15440, pl. 3911, act. field 162182
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 581 and sa.provider = 'salesforce';
SELECT * FROM automated_report_results order by id desc;
select * from features;
select * from team_features where feature_id = 40;
select * from teams where id = 556;
select * from automated_reports;
where id = 54; # 4fdd41f6-dcf0-30d0-b339-7345381b6044 , ["pdf","podcast"]
SELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;
select * from automated_report_results order by id desc;
SELECT * FROM automated_report_results WHERE id = 1919;
select * from automated_report_results WHERE report_id = 54;
select * from opportunities where id = 7594349;
SELECT * FROM teams WHERE name LIKE '%Les%'; # 711, 692, 16067 - [EMAIL]
select * from playbooks where team_id = 711; # event 226147
SELECT * FROM playbook_categories WHERE playbook_id = 5515;
SELECT * FROM crm_fields WHERE crm_configuration_id = 692 and object_type = 'event';
SELECT * FROM crm_fields WHERE id = 226147;
SELECT * FROM crm_field_values WHERE crm_field_id = 226147;
SELECT * FROM crm_configurations WHERE id = 692;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 711 and sa.provider = 'salesforce';
SELECT * FROM crm_profiles cp JOIN users u on u.id = cp.user_id WHERE u.team_id = 711;
select * from leads;
select * from calendars;
SELECT
t.id AS team_id,
t.name,
LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1)) AS calendar_domain
FROM teams t
JOIN users u ON u.team_id = t.id
JOIN calendars c ON c.user_id = u.id AND c.status = 'active' AND c.calendar_provider_id LIKE '%@%'
LEFT JOIN team_domains td
ON td.team_id = t.id
AND td.deleted_at IS NULL
AND td.domain = LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1))
GROUP BY t.id, t.name, calendar_domain
ORDER BY t.name, calendar_domain;
select * from users u join calendars c on c.user_id = u.id
where u.team_id = 882;
select * from activities where id = 74049485; # team 563 crm 537
select * from activities where id = 73272382; # team 563 crm 537
select * from activities where id = 64400389; # team 563 crm 537
select * from activities where id = 58081273; # team 563 crm 537
select * from activities where id = 54520297; # team 563 crm 537
select * from participants where activity_id = 58081273;
select * from activities where crm_configuration_id = 537 and provider = 'aircall'
and account_id = 19003658 order by updated_at desc;
select * from contacts where crm_configuration_id = 537 and id = 35957759;
select * from accounts where crm_configuration_id = 537 and id = 19003658;
select * from automated_report_results where id = 1976;
select * from automated_reports where id = 583;
select * from activity_searches where id = 87714;
select * from activity_search_filters where activity_search_id = 87714;
SELECT * FROM activities WHERE uuid_to_bin('8827f672-202d-4162-9d04-73ff5f0566a9') = uuid
or uuid_to_bin('47842446-af51-4bcb-854f-cc6560290101') = uuid;
Sync Changes
Hide This Notification
Code changed:
Hide
4
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands\Dev;
use Jiminny\Console\Commands\Command;
use Jiminny\Contracts\Http\RateLimited;
use Jiminny\Models\Activity\Provider;
use Jiminny\Models\Crm\Configuration;
class AddRateLimitCommand extends Command
{
private const TYPE_ACTIVITY_PROVIDER = Provider::class;
private const TYPE_CRM_CONFIGURATION = Configuration::class;
private const RATE_LIMITED_TYPES = [self::TYPE_ACTIVITY_PROVIDER, self::TYPE_CRM_CONFIGURATION];
protected $signature = 'jiminny:add-rate-limit';
public function handle(): void
{
$type = $this->choice('Choose type', self::RATE_LIMITED_TYPES);
$id = $this->ask(sprintf('Enter an ID of the %s', $type));
$quota = (int) $this->ask('Enter number of requests');
$window = (int) $this->ask('Enter request window in seconds');
$rateLimited = (new $type())::find($id);
if (! $rateLimited instanceof RateLimited) {
$this->error('Model not found');
return;
}
$rateLimited->rateLimits()->updateOrCreate([
'limited_id' => $id,
'limited_type' => $type,
'quota' => $quota,
'window' => $window,
]);
$this->info('Done');
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl, folder
ActionItems, folder
Activity, folder
ActivityAnalytics, folder
ActivitySearch, folder
AiActivityType, folder
AiAutomation, folder
AiCallScoring, folder
AskAnything, folder
Dtos, folder
Events, folder
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi, folder
AWS, folder
BillingManagement, folder
Cache, folder
CoachingFeedback, folder
Country, folder
CustomerApi, folder
Database, folder
Datadog, folder
DateTime, folder
DealInsights, folder
DealRisks, folder
ElasticSearch, folder
Eloquent, folder
Encoding, folder
Encryption, folder
ES, folder
Faker, folder
FeatureFlags, folder
FFMpeg, folder
FileSystem, folder
Gecko, folder
Gong, folder
GuzzleHttp, folder
KeyPoints, folder
Kiosk, folder
LanguageDetection, folder
LiveFeed, folder
Locks, folder
Math, folder
MediaPipeline, folder
MeetingBot, folder
MobileSettings, folder
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage, folder
Playlist, folder
Prophet, folder
ProphetAi, folder
ProsperWorks, folder...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
1598
|
64
|
25
|
2026-05-07T09:00:52.641615+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778144452641_m2.jpg...
|
Slack
|
Stoyan Tanev (DM) - Jiminny Inc - 4 new items - Sl Stoyan Tanev (DM) - Jiminny Inc - 4 new items - Slack...
|
True
|
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
All, 3 unread
DMs
Add new tab
Reminder
DM
Reschedule
Mark as unread
Clear
More actions
Stoyan Tanev:
Здрасти, за този тикет:
[URL_WITH_CREDENTIALS] Ivanov
@Nikolay Ivanov
transitioned a Bug you are watching from
Code Review
⟶
Deployed
…
Wednesday, April 29th
Aneliya Angelova
Aneliya Angelova, Nikolay Yankov, Steliyan Georgiev
Apr 29th
да
Stoyan Tanev
DM
Apr 29th
трябва ли да синкваме нещо от наша страна?
Tuesday, April 28th
Stefka Stoyanova
Thread
Apr 28th
тия тикети е добре да влезнат в другия спринт ли? сложете някакви естимейти тогава
Ves
Thread in
DM
:
исках да те питам credentials на AWS. Направих server на постмарк за QAI но не знам как да добавя key, май вече не е през env. Има ли някакви инструкции?
Apr 28th
смени го в Circle CI env на новия токен който си направил
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Stoyan Tanev
Apr 15th at 1:34:21 PM
1:34 PM
Да пускам го
Jump to date
Lukas Kovalik
Apr 16th at 2:02:18 PM
2:02 PM
здрасти
Stoyan Tanev
Apr 16th at 2:04:46 PM
2:04 PM
Здравей
Lukas Kovalik
Apr 16th at 2:08:12 PM
2:08 PM
проблемът от вчера се оказа козметичен
Apr 16th at 2:08:18 PM
2:08
все пак го има
Apr 16th at 2:08:57 PM
2:08
говорих със integration-app и ще видим дали си го оправят те или пак при нас
1 reaction, react with white check mark emoji
1
Add reaction…
Apr 16th at 2:09:18 PM
2:09
интеграция работи само не ни казват че е минало успешно
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 16th at 2:09:44 PM
2:09
ръчно го смених в база social account на connected
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 16th at 2:09:51 PM
2:09
и си работи всичко
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 16th at 2:10:15 PM
2:10
просто всеки път трябва да се смени на ръка преди да го фикснем
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 16th at 2:10:35 PM
2:10
само да го имаш предвид ако се появи нещо междувременно
1 reaction, react with raised hands emoji
1
Add reaction…
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Stoyan Tanev
Apr 16th at 2:10:36 PM
2:10 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
Jump to date
Saved for later • Due < 1 minute ago
Stoyan Tanev
Apr 29th at 1:02:14 PM
1:02 PM
Здрасти, за този тикет:
https://jiminny.atlassian.net/browse/SRD-6793
https://jiminny.atlassian.net/browse/SRD-6793
Jira Cloud
Jira Cloud
Jira Cloud Bug SRD-6793 Les Mills activity types not pulling in Bug SRD-6793 in Jira Cloud Preview in Slack Status Closed Assignee Stoyan Tanev As of Wednesday at 1:02 PM Refresh Open in Jira ✨ Summarise
Les Mills activity types not pulling in
Bug SRD-6793 in Jira Cloud
Preview in Slack
Status
Closed
Assignee
Stoyan Tanev
As of Wednesday at 1:02 PM
Refresh
Open in Jira
✨ Summarise
Open in browser
Open
Share Bug SRD-6793
View conversations
More actions
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Remove from Later
More actions
Apr 29th at 1:02:45 PM
1:02
Клиента твърди, че са направили нужните промени, но пак не пускаме активити типа в сф
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 29th at 1:02:53 PM
1:02
трябва ли да синкваме нещо от наша страна?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Channel...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.0056515955,"top":0.058260176,"width":0.011968086,"height":0.028731046},"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.0029920214,"top":0.10055866,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"bounds":{"left":0.0066489363,"top":0.13806863,"width":0.009973404,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.0029920214,"top":0.15482841,"width":0.017287234,"height":0.054269753},"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.0076462766,"top":0.19233839,"width":0.007978723,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.0029920214,"top":0.20909816,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"bounds":{"left":0.004986702,"top":0.24660814,"width":0.012965426,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.005319149,"top":0.24660814,"width":0.0026595744,"height":0.011173184}},{"char_start":1,"char_count":7,"bounds":{"left":0.0076462766,"top":0.24660814,"width":0.010638298,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.0029920214,"top":0.26336792,"width":0.017287234,"height":0.054269753},"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.0076462766,"top":0.3008779,"width":0.0076462766,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.007978723,"top":0.3008779,"width":0.0019946808,"height":0.011173184}},{"char_start":1,"char_count":4,"bounds":{"left":0.009973404,"top":0.3008779,"width":0.0056515955,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.0029920214,"top":0.31763768,"width":0.017287234,"height":0.054269753},"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.00731383,"top":0.35514766,"width":0.008643617,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.00731383,"top":0.35514766,"width":0.0019946808,"height":0.011173184}},{"char_start":1,"char_count":4,"bounds":{"left":0.00930851,"top":0.35514766,"width":0.0066489363,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.0029920214,"top":0.3719074,"width":0.017287234,"height":0.054269753},"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.006981383,"top":0.4094174,"width":0.008976064,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.00731383,"top":0.4094174,"width":0.0033244682,"height":0.011173184}},{"char_start":1,"char_count":3,"bounds":{"left":0.010638298,"top":0.4094174,"width":0.0056515955,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"All, 3 unread","depth":19,"bounds":{"left":0.028922873,"top":0.09497207,"width":0.021276595,"height":0.026336791},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXRadioButton","text":"DMs","depth":19,"bounds":{"left":0.050199468,"top":0.09497207,"width":0.01462766,"height":0.026336791},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Add new tab","depth":20,"bounds":{"left":0.0674867,"top":0.09497207,"width":0.005319149,"height":0.026336791},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Reminder","depth":22,"bounds":{"left":0.047872342,"top":0.18276137,"width":0.020944148,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.047872342,"top":0.18276137,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":7,"bounds":{"left":0.05086436,"top":0.18276137,"width":0.017952127,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"DM","depth":22,"bounds":{"left":0.047872342,"top":0.19952115,"width":0.00731383,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Reschedule","depth":23,"bounds":{"left":0.0774601,"top":0.17797287,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Mark as unread","depth":23,"bounds":{"left":0.08809841,"top":0.17797287,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Clear","depth":23,"bounds":{"left":0.0987367,"top":0.17797287,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":23,"bounds":{"left":0.109375,"top":0.17797287,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Stoyan Tanev:","depth":23,"bounds":{"left":0.03324468,"top":0.21787709,"width":0.03125,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03324468,"top":0.21787709,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":12,"bounds":{"left":0.035904255,"top":0.21787709,"width":0.027593086,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Здрасти, за този тикет:","depth":23,"bounds":{"left":0.064494684,"top":0.21787709,"width":0.05319149,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.064494684,"top":0.21787709,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":22,"bounds":{"left":0.06715426,"top":0.21787709,"width":0.050531916,"height":0.014365523}}],"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/SRD-6793","depth":23,"bounds":{"left":0.03324468,"top":0.23543495,"width":0.08577128,"height":0.031923383},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/SRD-6793","depth":24,"bounds":{"left":0.03324468,"top":0.23543495,"width":0.08577128,"height":0.031923383},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03324468,"top":0.23543495,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":44,"bounds":{"left":0.03324468,"top":0.23543495,"width":0.08610372,"height":0.031923383}}],"role_description":"text"},{"role":"AXButton","text":"Mark complete","depth":23,"bounds":{"left":0.03324468,"top":0.2434158,"width":0.04255319,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Reminder","depth":22,"bounds":{"left":0.047872342,"top":0.29449323,"width":0.021609042,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.047872342,"top":0.29449323,"width":0.0033244682,"height":0.014365523}},{"char_start":1,"char_count":7,"bounds":{"left":0.05119681,"top":0.29449323,"width":0.018284574,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Post in","depth":22,"bounds":{"left":0.047872342,"top":0.31125298,"width":0.013297873,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.047872342,"top":0.31125298,"width":0.0026595744,"height":0.012769354}},{"char_start":1,"char_count":6,"bounds":{"left":0.050531916,"top":0.31125298,"width":0.010638298,"height":0.012769354}}],"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":22,"bounds":{"left":0.062832445,"top":0.32881084,"width":0.00831117,"height":0.02952913},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.06781915,"top":0.3120511,"width":0.0023271276,"height":0.011173184}},{"char_start":1,"char_count":6,"bounds":{"left":0.0631649,"top":0.32960895,"width":0.00831117,"height":0.028731046}}],"role_description":"text"},{"role":"AXStaticText","text":"Incomplete","depth":22,"bounds":{"left":0.073803194,"top":0.29688746,"width":0.019614361,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.07413564,"top":0.29688746,"width":0.0013297872,"height":0.011971269}},{"char_start":1,"char_count":9,"bounds":{"left":0.07513298,"top":0.29688746,"width":0.01861702,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"Just now","depth":22,"bounds":{"left":0.102726065,"top":0.29608938,"width":0.017287234,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.102726065,"top":0.29608938,"width":0.0019946808,"height":0.013567438}},{"char_start":1,"char_count":7,"bounds":{"left":0.10472074,"top":0.29608938,"width":0.015292553,"height":0.013567438}}],"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov:","depth":23,"bounds":{"left":0.03324468,"top":0.32960895,"width":0.034574468,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03324468,"top":0.32960895,"width":0.0039893617,"height":0.014365523}},{"char_start":1,"char_count":14,"bounds":{"left":0.03723404,"top":0.32960895,"width":0.02925532,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"For those using","depth":23,"bounds":{"left":0.0674867,"top":0.32960895,"width":0.034906916,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.06781915,"top":0.32960895,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":14,"bounds":{"left":0.07047872,"top":0.32960895,"width":0.030917553,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"make cs-fix","depth":24,"bounds":{"left":0.03324468,"top":0.32960895,"width":0.08610372,"height":0.031923383},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"and getting annoyed by how long it takes (since it scans the entire project), you can now use","depth":23,"bounds":{"left":0.03324468,"top":0.3471668,"width":0.08577128,"height":0.040702313},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.04654255,"top":0.3471668,"width":0.0016622341,"height":0.014365523}},{"char_start":1,"char_count":92,"bounds":{"left":0.03324468,"top":0.3471668,"width":0.08577128,"height":0.049481247}}],"role_description":"text"},{"role":"AXStaticText","text":"make cs-fix-branch","depth":24,"bounds":{"left":0.03324468,"top":0.38467678,"width":0.08510638,"height":0.0031923384},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":". It will fix only the files that differ from","depth":23,"bounds":{"left":0.03324468,"top":0.38707104,"width":0.08643617,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"master","depth":24,"bounds":{"left":0.039893616,"top":0.38707104,"width":0.014295213,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":", and it runs in just a couple of seconds","depth":23,"bounds":{"left":0.03324468,"top":0.38707104,"width":0.08610372,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Mark complete","depth":23,"bounds":{"left":0.03324468,"top":0.35514766,"width":0.04255319,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Toast","depth":22,"bounds":{"left":0.047872342,"top":0.40622506,"width":0.011635638,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.047872342,"top":0.40622506,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":4,"bounds":{"left":0.050199468,"top":0.40622506,"width":0.00930851,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"App","depth":22,"bounds":{"left":0.047872342,"top":0.42298484,"width":0.0076462766,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.047872342,"top":0.42298484,"width":0.0029920214,"height":0.012769354}},{"char_start":1,"char_count":2,"bounds":{"left":0.05086436,"top":0.42298484,"width":0.004986702,"height":0.012769354}}],"role_description":"text"},{"role":"AXStaticText","text":"10:00 AM","depth":22,"bounds":{"left":0.10073138,"top":0.40782124,"width":0.019281914,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10106383,"top":0.40782124,"width":0.0026595744,"height":0.012769354}},{"char_start":1,"char_count":7,"bounds":{"left":0.103390954,"top":0.40782124,"width":0.01662234,"height":0.012769354}}],"role_description":"text"},{"role":"AXStaticText","text":"[no preview available]","depth":23,"bounds":{"left":0.03324468,"top":0.44134077,"width":0.04720745,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03324468,"top":0.44134077,"width":0.0013297872,"height":0.014365523}},{"char_start":1,"char_count":21,"bounds":{"left":0.034574468,"top":0.44134077,"width":0.045877658,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Monday, May 4th","depth":21,"bounds":{"left":0.059507977,"top":0.49481246,"width":0.033909574,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.059840426,"top":0.49561054,"width":0.0039893617,"height":0.012769354}},{"char_start":1,"char_count":14,"bounds":{"left":0.06382979,"top":0.49561054,"width":0.029587766,"height":0.012769354}}],"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":22,"bounds":{"left":0.047872342,"top":0.5403033,"width":0.021609042,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.047872342,"top":0.5403033,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":9,"bounds":{"left":0.049867023,"top":0.5403033,"width":0.019946808,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"App","depth":22,"bounds":{"left":0.047872342,"top":0.55706304,"width":0.0076462766,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.047872342,"top":0.55706304,"width":0.0029920214,"height":0.012769354}},{"char_start":1,"char_count":2,"bounds":{"left":0.05086436,"top":0.55706304,"width":0.004986702,"height":0.012769354}}],"role_description":"text"},{"role":"AXStaticText","text":"Monday","depth":22,"bounds":{"left":0.1043883,"top":0.54189944,"width":0.015625,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.1043883,"top":0.54189944,"width":0.0043218085,"height":0.012769354}},{"char_start":1,"char_count":5,"bounds":{"left":0.10837766,"top":0.54189944,"width":0.011968086,"height":0.012769354}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.04055851,"top":0.575419,"width":0.0013297872,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"@Nikolay Ivanov","depth":23,"bounds":{"left":0.04155585,"top":0.5746209,"width":0.03856383,"height":0.015961692},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"@Nikolay Ivanov","depth":24,"bounds":{"left":0.042220745,"top":0.575419,"width":0.03723404,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.04255319,"top":0.575419,"width":0.0043218085,"height":0.014365523}},{"char_start":1,"char_count":14,"bounds":{"left":0.04654255,"top":0.575419,"width":0.032912236,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"transitioned a Bug you are watching from","depth":23,"bounds":{"left":0.03324468,"top":0.575419,"width":0.07978723,"height":0.031923383},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.080119684,"top":0.575419,"width":0.0013297872,"height":0.014365523}},{"char_start":1,"char_count":39,"bounds":{"left":0.03324468,"top":0.575419,"width":0.080119684,"height":0.031923383}}],"role_description":"text"},{"role":"AXStaticText","text":"Code Review","depth":23,"bounds":{"left":0.03324468,"top":0.59297687,"width":0.07712766,"height":0.031923383},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.09375,"top":0.59297687,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":10,"bounds":{"left":0.03324468,"top":0.59297687,"width":0.0774601,"height":0.031923383}}],"role_description":"text"},{"role":"AXStaticText","text":"⟶","depth":23,"bounds":{"left":0.04920213,"top":0.6105347,"width":0.007978723,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Deployed","depth":23,"bounds":{"left":0.056848403,"top":0.6105347,"width":0.021609042,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.05718085,"top":0.6105347,"width":0.0039893617,"height":0.014365523}},{"char_start":1,"char_count":7,"bounds":{"left":0.060837764,"top":0.6105347,"width":0.01761968,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"…","depth":23,"bounds":{"left":0.078125,"top":0.6105347,"width":0.0039893617,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Wednesday, April 29th","depth":21,"bounds":{"left":0.054521278,"top":0.64644855,"width":0.043882977,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.054853722,"top":0.6472466,"width":0.0043218085,"height":0.012769354}},{"char_start":1,"char_count":20,"bounds":{"left":0.059175532,"top":0.6472466,"width":0.03956117,"height":0.012769354}}],"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":22,"bounds":{"left":0.047872342,"top":0.69193935,"width":0.03756649,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.047872342,"top":0.69193935,"width":0.0033244682,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.05119681,"top":0.69193935,"width":0.034242023,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova, Nikolay Yankov, Steliyan Georgiev","depth":22,"bounds":{"left":0.04920213,"top":0.70790106,"width":0.05086436,"height":0.0015961692},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Apr 29th","depth":22,"bounds":{"left":0.10305851,"top":0.6935355,"width":0.016954787,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10305851,"top":0.6935355,"width":0.0033244682,"height":0.012769354}},{"char_start":1,"char_count":7,"bounds":{"left":0.10605053,"top":0.6935355,"width":0.014295213,"height":0.012769354}}],"role_description":"text"},{"role":"AXStaticText","text":"да","depth":23,"bounds":{"left":0.03324468,"top":0.7086991,"width":0.0056515955,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":22,"bounds":{"left":0.047872342,"top":0.7086991,"width":0.028922873,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"DM","depth":22,"bounds":{"left":0.047872342,"top":0.7086991,"width":0.00731383,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Apr 29th","depth":22,"bounds":{"left":0.10305851,"top":0.7086991,"width":0.016954787,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"трябва ли да синкваме нещо от наша страна?","depth":23,"bounds":{"left":0.03324468,"top":0.7086991,"width":0.07413564,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Tuesday, April 28th","depth":21,"bounds":{"left":0.05817819,"top":0.7086991,"width":0.036901597,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":22,"bounds":{"left":0.047872342,"top":0.7086991,"width":0.03756649,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Thread","depth":22,"bounds":{"left":0.047872342,"top":0.7086991,"width":0.013297873,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Apr 28th","depth":22,"bounds":{"left":0.10305851,"top":0.7086991,"width":0.016954787,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"тия тикети е добре да влезнат в другия спринт ли? сложете някакви естимейти тогава","depth":23,"bounds":{"left":0.03324468,"top":0.7086991,"width":0.08643617,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Ves","depth":22,"bounds":{"left":0.047872342,"top":0.7086991,"width":0.0076462766,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Thread in","depth":22,"bounds":{"left":0.047872342,"top":0.7086991,"width":0.017952127,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.06549202,"top":0.7086991,"width":0.0013297872,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"DM","depth":22,"bounds":{"left":0.06648936,"top":0.7086991,"width":0.0076462766,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":":","depth":22,"bounds":{"left":0.073803194,"top":0.7086991,"width":0.0023271276,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"исках да те питам credentials на AWS. Направих server на постмарк за QAI но не знам как да добавя key, май вече не е през env. Има ли някакви инструкции?","depth":22,"bounds":{"left":0.047872342,"top":0.7086991,"width":0.05418883,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Apr 28th","depth":22,"bounds":{"left":0.10305851,"top":0.7086991,"width":0.016954787,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"смени го в Circle CI env на новия токен който си направил","depth":23,"bounds":{"left":0.03324468,"top":0.7086991,"width":0.075465426,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.13530585,"top":0.09177973,"width":0.030585106,"height":0.030327214},"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.14461437,"top":0.10055866,"width":0.01861702,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.14461437,"top":0.10055866,"width":0.0039893617,"height":0.012769354}},{"char_start":1,"char_count":7,"bounds":{"left":0.14860372,"top":0.10055866,"width":0.014960106,"height":0.012769354}}],"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"bounds":{"left":0.16722074,"top":0.09177973,"width":0.033909574,"height":0.030327214},"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.17652926,"top":0.10055866,"width":0.021941489,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.17652926,"top":0.10055866,"width":0.0033244682,"height":0.012769354}},{"char_start":1,"char_count":9,"bounds":{"left":0.17952128,"top":0.10055866,"width":0.019281914,"height":0.012769354}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.20246011,"top":0.09177973,"width":0.020944148,"height":0.030327214},"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.21176861,"top":0.10055866,"width":0.008976064,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.21176861,"top":0.10055866,"width":0.0026595744,"height":0.012769354}},{"char_start":1,"char_count":4,"bounds":{"left":0.21442819,"top":0.10055866,"width":0.0063164895,"height":0.012769354}}],"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.2244016,"top":0.09177973,"width":0.010970744,"height":0.030327214},"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,"bounds":{"left":0.12965426,"top":0.0518755,"width":0.015625,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"bounds":{"left":0.12965426,"top":0.0518755,"width":0.0076462766,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"bounds":{"left":0.12965426,"top":0.0518755,"width":0.013962766,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Stoyan Tanev","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Apr 15th at 1:34:21 PM","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:34 PM","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Да пускам го","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.2523271,"top":0.12689546,"width":0.05285904,"height":0.022346368},"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":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Apr 16th at 2:02:18 PM","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:02 PM","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"здрасти","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Stoyan Tanev","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Apr 16th at 2:04:46 PM","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:04 PM","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Здравей","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Apr 16th at 2:08:12 PM","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:08 PM","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"проблемът от вчера се оказа козметичен","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Apr 16th at 2:08:18 PM","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:08","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"все пак го има","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Apr 16th at 2:08:57 PM","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:08","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"говорих със integration-app и ще видим дали си го оправят те или пак при нас","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXCheckBox","text":"1 reaction, react with white check mark emoji","depth":24,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Add reaction…","depth":24,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Apr 16th at 2:09:18 PM","depth":24,"bounds":{"left":0.140625,"top":0.12849163,"width":0.007978723,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:09","depth":25,"bounds":{"left":0.140625,"top":0.12849163,"width":0.007978723,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.140625,"top":0.12849163,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":3,"bounds":{"left":0.14295213,"top":0.12849163,"width":0.005984043,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"интеграция работи само не ни казват че е минало успешно","depth":24,"bounds":{"left":0.1512633,"top":0.12609737,"width":0.13663563,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.1512633,"top":0.12609737,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":54,"bounds":{"left":0.15425532,"top":0.12609737,"width":0.13364361,"height":0.014365523}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":false,"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":false,"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":false,"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":"Apr 16th at 2:09:44 PM","depth":24,"bounds":{"left":0.140625,"top":0.15243416,"width":0.007978723,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:09","depth":25,"bounds":{"left":0.140625,"top":0.15243416,"width":0.007978723,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.140625,"top":0.15243416,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":3,"bounds":{"left":0.14295213,"top":0.15243416,"width":0.005984043,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"ръчно го смених в база social account на connected","depth":24,"bounds":{"left":0.1512633,"top":0.15003991,"width":0.11569149,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.1512633,"top":0.15003991,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":49,"bounds":{"left":0.15392287,"top":0.15003991,"width":0.11303192,"height":0.014365523}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":false,"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":false,"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":false,"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":"Apr 16th at 2:09:51 PM","depth":24,"bounds":{"left":0.140625,"top":0.1763767,"width":0.007978723,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:09","depth":25,"bounds":{"left":0.140625,"top":0.1763767,"width":0.007978723,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.140625,"top":0.1763767,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":3,"bounds":{"left":0.14295213,"top":0.1763767,"width":0.005984043,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"и си работи всичко","depth":24,"bounds":{"left":0.1512633,"top":0.17398244,"width":0.043882977,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.1512633,"top":0.17398244,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":17,"bounds":{"left":0.15425532,"top":0.17398244,"width":0.04089096,"height":0.014365523}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":false,"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":false,"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":false,"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":"Apr 16th at 2:10:15 PM","depth":24,"bounds":{"left":0.140625,"top":0.20031923,"width":0.007978723,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:10","depth":25,"bounds":{"left":0.140625,"top":0.20031923,"width":0.007978723,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.140625,"top":0.20031923,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":3,"bounds":{"left":0.14295213,"top":0.20031923,"width":0.005984043,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"просто всеки път трябва да се смени на ръка преди да го фикснем","depth":24,"bounds":{"left":0.1512633,"top":0.19792499,"width":0.15325798,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.1512633,"top":0.19792499,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":62,"bounds":{"left":0.15425532,"top":0.19792499,"width":0.15026596,"height":0.014365523}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":false,"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":false,"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":false,"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":"Apr 16th at 2:10:35 PM","depth":24,"bounds":{"left":0.140625,"top":0.22426178,"width":0.007978723,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:10","depth":25,"bounds":{"left":0.140625,"top":0.22426178,"width":0.007978723,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"само да го имаш предвид ако се появи нещо междувременно","depth":24,"bounds":{"left":0.1512633,"top":0.22186752,"width":0.14261968,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"1 reaction, react with raised hands emoji","depth":24,"bounds":{"left":0.1512633,"top":0.24102154,"width":0.014295213,"height":0.01915403},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":25,"bounds":{"left":0.16057181,"top":0.2442139,"width":0.0023271276,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Add reaction…","depth":24,"bounds":{"left":0.16655585,"top":0.24102154,"width":0.011635638,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":false,"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":false,"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":false,"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":"Stoyan Tanev","depth":23,"bounds":{"left":0.1512633,"top":0.2697526,"width":0.029587766,"height":0.017557861},"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.1875,"top":0.27134877,"width":0.0026595744,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 16th at 2:10:36 PM","depth":23,"bounds":{"left":0.18982713,"top":0.273743,"width":0.015292553,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:10 PM","depth":24,"bounds":{"left":0.18982713,"top":0.273743,"width":0.015292553,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Ясно, добре ще го имам в предвид","depth":24,"bounds":{"left":0.1512633,"top":0.28890663,"width":0.08045213,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":false,"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":false,"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":false,"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":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.25,"top":0.31923383,"width":0.057513297,"height":0.022346368},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Saved for later • Due < 1 minute ago","depth":23,"bounds":{"left":0.1512633,"top":0.35115722,"width":0.06981383,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Stoyan Tanev","depth":23,"bounds":{"left":0.1512633,"top":0.36552274,"width":0.029587766,"height":0.017557861},"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.1875,"top":0.36711892,"width":0.0026595744,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 29th at 1:02:14 PM","depth":23,"bounds":{"left":0.18982713,"top":0.36951315,"width":0.015292553,"height":0.011971269},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:02 PM","depth":24,"bounds":{"left":0.18982713,"top":0.36951315,"width":0.015292553,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Здрасти, за този тикет:","depth":24,"bounds":{"left":0.1512633,"top":0.38467678,"width":0.054521278,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/SRD-6793","depth":24,"bounds":{"left":0.20545213,"top":0.38467678,"width":0.103390954,"height":0.014365523},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/SRD-6793","depth":25,"bounds":{"left":0.20545213,"top":0.38467678,"width":0.103390954,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.1512633,"top":0.40782124,"width":0.018949468,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Jira Cloud","depth":23,"bounds":{"left":0.17121011,"top":0.40782124,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"Jira Cloud Bug SRD-6793 Les Mills activity types not pulling in Bug SRD-6793 in Jira Cloud Preview in Slack Status Closed Assignee Stoyan Tanev As of Wednesday at 1:02 PM Refresh Open in Jira ✨ Summarise","depth":25,"bounds":{"left":0.1512633,"top":0.424581,"width":0.15957446,"height":0.1348763},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Les Mills activity types not pulling in","depth":26,"bounds":{"left":0.17154256,"top":0.43814844,"width":0.080119684,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Bug SRD-6793 in Jira Cloud","depth":27,"bounds":{"left":0.17154256,"top":0.45411015,"width":0.05319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"bounds":{"left":0.17154256,"top":0.45411015,"width":0.03125,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Status","depth":26,"bounds":{"left":0.17154256,"top":0.4772546,"width":0.011635638,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Closed","depth":26,"bounds":{"left":0.17287233,"top":0.4964086,"width":0.014960106,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Assignee","depth":26,"bounds":{"left":0.19680852,"top":0.4772546,"width":0.017287234,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":27,"bounds":{"left":0.20711437,"top":0.49720672,"width":0.025598405,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"As of Wednesday at 1:02 PM","depth":27,"bounds":{"left":0.15558511,"top":0.53471667,"width":0.05518617,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Refresh","depth":27,"bounds":{"left":0.21176861,"top":0.53790903,"width":0.01462766,"height":0.006384677},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open in Jira","depth":27,"bounds":{"left":0.24035904,"top":0.52992815,"width":0.03125,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"✨ Summarise","depth":27,"bounds":{"left":0.27260637,"top":0.52992815,"width":0.03523936,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Open in browser","depth":26,"bounds":{"left":0.24734043,"top":0.43814844,"width":0.022938829,"height":0.025538707},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Open","depth":27,"bounds":{"left":0.25664893,"top":0.44373503,"width":0.010970744,"height":0.013567438},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Share Bug SRD-6793","depth":26,"bounds":{"left":0.27327126,"top":0.43814844,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View conversations","depth":26,"bounds":{"left":0.2839096,"top":0.43814844,"width":0.010638298,"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":26,"bounds":{"left":0.2945479,"top":0.43814844,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.33543882,"top":0.33758977,"width":0.010638298,"height":0.025538707},"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.3460771,"top":0.33758977,"width":0.010638298,"height":0.025538707},"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.3567154,"top":0.33758977,"width":0.010638298,"height":0.025538707},"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.36735374,"top":0.33758977,"width":0.010638298,"height":0.025538707},"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,"bounds":{"left":0.37799203,"top":0.33758977,"width":0.010638298,"height":0.025538707},"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,"bounds":{"left":0.38863033,"top":0.33758977,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Remove from Later","depth":25,"bounds":{"left":0.39926863,"top":0.33758977,"width":0.010638298,"height":0.025538707},"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,"bounds":{"left":0.40990692,"top":0.33758977,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Apr 29th at 1:02:45 PM","depth":24,"bounds":{"left":0.140625,"top":0.57302475,"width":0.007978723,"height":0.011971269},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:02","depth":25,"bounds":{"left":0.140625,"top":0.57302475,"width":0.007978723,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Клиента твърди, че са направили нужните промени, но пак не пускаме активити типа в сф","depth":24,"bounds":{"left":0.1512633,"top":0.5706305,"width":0.20910904,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":false,"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":false,"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":false,"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":"Apr 29th at 1:02:53 PM","depth":24,"bounds":{"left":0.140625,"top":0.5969673,"width":0.007978723,"height":0.011971269},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:02","depth":25,"bounds":{"left":0.140625,"top":0.5969673,"width":0.007978723,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"трябва ли да синкваме нещо от наша страна?","depth":24,"bounds":{"left":0.1512633,"top":0.594573,"width":0.10472074,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":false,"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":false,"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":false,"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.13696809,"top":0.6272945,"width":0.2835771,"height":0.030327214},"on_screen":true,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Channel","depth":11,"bounds":{"left":0.0,"top":0.7126895,"width":0.017287234,"height":0.0007980846},"on_screen":true,"role_description":"text"}]...
|
-8095015545399178329
|
-1425365564946724770
|
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
All, 3 unread
DMs
Add new tab
Reminder
DM
Reschedule
Mark as unread
Clear
More actions
Stoyan Tanev:
Здрасти, за този тикет:
[URL_WITH_CREDENTIALS] Ivanov
@Nikolay Ivanov
transitioned a Bug you are watching from
Code Review
⟶
Deployed
…
Wednesday, April 29th
Aneliya Angelova
Aneliya Angelova, Nikolay Yankov, Steliyan Georgiev
Apr 29th
да
Stoyan Tanev
DM
Apr 29th
трябва ли да синкваме нещо от наша страна?
Tuesday, April 28th
Stefka Stoyanova
Thread
Apr 28th
тия тикети е добре да влезнат в другия спринт ли? сложете някакви естимейти тогава
Ves
Thread in
DM
:
исках да те питам credentials на AWS. Направих server на постмарк за QAI но не знам как да добавя key, май вече не е през env. Има ли някакви инструкции?
Apr 28th
смени го в Circle CI env на новия токен който си направил
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Stoyan Tanev
Apr 15th at 1:34:21 PM
1:34 PM
Да пускам го
Jump to date
Lukas Kovalik
Apr 16th at 2:02:18 PM
2:02 PM
здрасти
Stoyan Tanev
Apr 16th at 2:04:46 PM
2:04 PM
Здравей
Lukas Kovalik
Apr 16th at 2:08:12 PM
2:08 PM
проблемът от вчера се оказа козметичен
Apr 16th at 2:08:18 PM
2:08
все пак го има
Apr 16th at 2:08:57 PM
2:08
говорих със integration-app и ще видим дали си го оправят те или пак при нас
1 reaction, react with white check mark emoji
1
Add reaction…
Apr 16th at 2:09:18 PM
2:09
интеграция работи само не ни казват че е минало успешно
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 16th at 2:09:44 PM
2:09
ръчно го смених в база social account на connected
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 16th at 2:09:51 PM
2:09
и си работи всичко
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 16th at 2:10:15 PM
2:10
просто всеки път трябва да се смени на ръка преди да го фикснем
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 16th at 2:10:35 PM
2:10
само да го имаш предвид ако се появи нещо междувременно
1 reaction, react with raised hands emoji
1
Add reaction…
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Stoyan Tanev
Apr 16th at 2:10:36 PM
2:10 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
Jump to date
Saved for later • Due < 1 minute ago
Stoyan Tanev
Apr 29th at 1:02:14 PM
1:02 PM
Здрасти, за този тикет:
https://jiminny.atlassian.net/browse/SRD-6793
https://jiminny.atlassian.net/browse/SRD-6793
Jira Cloud
Jira Cloud
Jira Cloud Bug SRD-6793 Les Mills activity types not pulling in Bug SRD-6793 in Jira Cloud Preview in Slack Status Closed Assignee Stoyan Tanev As of Wednesday at 1:02 PM Refresh Open in Jira ✨ Summarise
Les Mills activity types not pulling in
Bug SRD-6793 in Jira Cloud
Preview in Slack
Status
Closed
Assignee
Stoyan Tanev
As of Wednesday at 1:02 PM
Refresh
Open in Jira
✨ Summarise
Open in browser
Open
Share Bug SRD-6793
View conversations
More actions
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Remove from Later
More actions
Apr 29th at 1:02:45 PM
1:02
Клиента твърди, че са направили нужните промени, но пак не пускаме активити типа в сф
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 29th at 1:02:53 PM
1:02
трябва ли да синкваме нещо от наша страна?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Channel
suppont Dally • In 3h100% 12Thu 7 May 12:00:52fravel.log4 SF jiminny@localhost]A HS_local (jiminny@localhost]« console [PROD] X# console [eu)dojiminny037 A1 A35 V64 ^HomeDMSSlackViewMistonWindowHelpQ Describe what you are looking forAC.MILVAll 3DMsReminderStoyan lanev: 3драсти, за тази тике...Mark comnleteReminderIncomplete Just nowPost in #...Nikolay Ivanov: For those using make ../ Mark comnlete10:00 AMIÍno preview available'Monday. May 4thLlira Gloud_@Nikolay Ivanov transitioned aBug you are watching from Code …Wednesday, April 29theAneliya AngelovaAor 29thlUseC) ChandeEmailJob.ohoP DeactivateUserJob.php(C) Setur DefaultSavedSean© SyncTolntercom.php© SyncToPlanhat.php© SyncToUserPilot.phpC. RaseProceccina.loh.nhnC) Dummv.loh.nhn© ImportRecallAlRecordingsJ© ImportRemoteTrackJob.ph(eulob,php(e) lohdicnatchor nhnStoyan TanevMessagesLo Add canvasUr Filesинтеграция работи само не ни казват че е м Thursday. April 16th ~рьчно го смених в база social account на connectedи си работи всичкопросто всеки път трябва да се смени на рька преди да го фикснемсамо да го имаш предвид ако се появи нещо междувременноStoyan Tanev 2:10 PMЯсно, добре ще го имам в предвидWednesdav. April 29thvSaved tor ater • Due ‹ 1 minute agoStoyan Tanev 1:02 PMЗлрасти, за този тикет: [URL_WITH_CREDENTIALS] =1$crmObject->value => $this->id,'activity' => $activity-›getIdO,'emitEvent' => $emitEvent,SupdateData =sentityldrield = null.// For leads and opportunities, also nullify the stage idif (Sstageld && in_array(ScrmObiect. [CrmObiect::LEAD. Crm0biect::0PPORTUNITY]..strictCascade• Hubspot Rate LimitDO l understand it correctly:Thinkinganother 990 in 90I'm working through a rate limitina scenario where 1000 jobs are dispatched immediately, each making a search request to HubSpot, and I need toconsider how the ProviderRateLimiter with a quota of 4 requests per second would handle this against HubSpot's actual limits of 4-5 requests per652654657 VS team1dSUBSTRING_INDEX(c.calendar_provider_id, '@', -1)) AS calendar_domairu 1<->1..n: ON U.team id = t.iddans c ON c.usen id = u.id AND c.status = 'active' AND c.calendar_provider_id LIKE '%0%'team domains tdteamid = tiodeleted at TS NUlI.domain = LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1)).id, t.name, calendar_domain.name, calendar_domain;rom users u join calendars c 1<->1.n: on c.user_id = u.idamid - 909.om activities where id = 74049485: # team 563 crm 537'om activities where id = 73272382: # team 563 crm 537rom activitles where 10 = 644005897# team 563 crm 537rom activitles where 1d = 58081215: # team 565 crm 557om activities where id = 54520297: # team 563 crm 537om participants where activity id = 58081273:rom activities where erm confiquration id = 557 and provider = 'aircallit 1d = 19003658 order by uodated at desc:rom contacts where erm confiquration 1d = 537 and 1d = 359577591om accounts where erm confiauration 1d e 537 and 1d = 190036581select * from automated_report_results where id = 1976;select * from automated_reports where id = 583;select * from activity_searches where id = 87714;select * from activity search filtens where activity search id = 87714÷SELECT * FROM activities WHERE uuid_to_bin('8827f672-202d-4162-9d04-73ff5f0566a9') = uuidor uuid_to_bin('47842446-af51-4bcb-854f-cc6560290101') = uuid;SELECT * FROM crm configurations WHERE provider = 'hubspot':select * from rate limits110Ask anvthina (*:4-D]<> Code Claude Qnus 17 MediumW Windsurf Teams66•521Po 4 space....
|
NULL
|
NULL
|
NULL
|
NULL
|
|
1599
|
63
|
24
|
2026-05-07T09:01:20.998002+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778144480998_m1.jpg...
|
Slack
|
Stoyan Tanev (DM) - Jiminny Inc - 4 new items - Sl Stoyan Tanev (DM) - Jiminny Inc - 4 new items - Slack...
|
True
|
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
All, 3 unread
DMs
Add new tab
Reminder
DM
Reschedule
Mark as unread
Clear
More actions
Stoyan Tanev:
Здрасти, за този тикет:
[URL_WITH_CREDENTIALS] Ivanov
@Nikolay Ivanov
transitioned a Bug you are watching from
Code Review
⟶
Deployed
…
Wednesday, April 29th
Aneliya Angelova
Aneliya Angelova, Nikolay Yankov, Steliyan Georgiev
Apr 29th
да
Stoyan Tanev
DM
Apr 29th
трябва ли да синкваме нещо от наша страна?
Tuesday, April 28th
Stefka Stoyanova
Thread
Apr 28th
тия тикети е добре да влезнат в другия спринт ли? сложете някакви естимейти тогава
Ves
Thread in
DM
:
исках да те питам credentials на AWS. Направих server на постмарк за QAI но не знам как да добавя key, май вече не е през env. Има ли някакви инструкции?
Apr 28th
смени го в Circle CI env на новия токен който си направил
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Stoyan Tanev
Apr 15th at 1:34:21 PM
1:34 PM
Да пускам го
Jump to date
Lukas Kovalik
Apr 16th at 2:02:18 PM
2:02 PM
здрасти
Stoyan Tanev
Apr 16th at 2:04:46 PM
2:04 PM
Здравей
Lukas Kovalik
Apr 16th at 2:08:12 PM
2:08 PM
проблемът от вчера се оказа козметичен
Apr 16th at 2:08:18 PM
2:08
все пак го има
Apr 16th at 2:08:57 PM
2:08
говорих със integration-app и ще видим дали си го оправят те или пак при нас
1 reaction, react with white check mark emoji
1
Add reaction…
Apr 16th at 2:09:18 PM
2:09
интеграция работи само не ни казват че е минало успешно
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 16th at 2:09:44 PM
2:09
ръчно го смених в база social account на connected
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 16th at 2:09:51 PM
2:09
и си работи всичко
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 16th at 2:10:15 PM
2:10
просто всеки път трябва да се смени на ръка преди да го фикснем
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 16th at 2:10:35 PM
2:10
само да го имаш предвид ако се появи нещо междувременно
1 reaction, react with raised hands emoji
1
Add reaction…
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Stoyan Tanev
Apr 16th at 2:10:36 PM
2:10 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
Jump to date
Saved for later • Due < 1 minute ago
Stoyan Tanev
Apr 29th at 1:02:14 PM
1:02 PM
Здрасти, за този тикет:
https://jiminny.atlassian.net/browse/SRD-6793
https://jiminny.atlassian.net/browse/SRD-6793
Jira Cloud
Jira Cloud
Jira Cloud Bug SRD-6793 Les Mills activity types not pulling in Bug SRD-6793 in Jira Cloud Preview in Slack Status Closed Assignee Stoyan Tanev As of Wednesday at 1:02 PM Refresh Open in Jira ✨ Summarise
Les Mills activity types not pulling in
Bug SRD-6793 in Jira Cloud
Preview in Slack
Status
Closed
Assignee
Stoyan Tanev
As of Wednesday at 1:02 PM
Refresh
Open in Jira
✨ Summarise
Open in browser
Open
Share Bug SRD-6793
View conversations
More actions
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Remove from Later
More actions
Apr 29th at 1:02:45 PM
1:02
Клиента твърди, че са направили нужните промени, но пак не пускаме активити типа в сф
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 29th at 1:02:53 PM
1:02
трябва ли да синкваме нещо от наша страна?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Channel...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"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":false,"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":true,"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":"AXRadioButton","text":"All, 3 unread","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXRadioButton","text":"DMs","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Add new tab","depth":20,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Reminder","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"DM","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Reschedule","depth":23,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Mark as unread","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Clear","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":23,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Stoyan Tanev:","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Здрасти, за този тикет:","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/SRD-6793","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/SRD-6793","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Mark complete","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Reminder","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Post in","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Incomplete","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Just now","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov:","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"For those using","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"make cs-fix","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"and getting annoyed by how long it takes (since it scans the entire project), you can now use","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"make cs-fix-branch","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":". It will fix only the files that differ from","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"master","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":", and it runs in just a couple of seconds","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Mark complete","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Toast","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"App","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"10:00 AM","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"[no preview available]","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Monday, May 4th","depth":21,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"App","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Monday","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"@Nikolay Ivanov","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"@Nikolay Ivanov","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"transitioned a Bug you are watching from","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Code Review","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"⟶","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Deployed","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"…","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Wednesday, April 29th","depth":21,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova, Nikolay Yankov, Steliyan Georgiev","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Apr 29th","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"да","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"DM","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Apr 29th","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"трябва ли да синкваме нещо от наша страна?","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Tuesday, April 28th","depth":21,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Thread","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Apr 28th","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"тия тикети е добре да влезнат в другия спринт ли? сложете някакви естимейти тогава","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Ves","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Thread in","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"DM","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":":","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"исках да те питам credentials на AWS. Направих server на постмарк за QAI но не знам как да добавя key, май вече не е през env. Има ли някакви инструкции?","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Apr 28th","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"смени го в Circle CI env на новия токен който си направил","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"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,"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,"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":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"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":true,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Stoyan Tanev","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Apr 15th at 1:34:21 PM","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:34 PM","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Да пускам го","depth":24,"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":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Apr 16th at 2:02:18 PM","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:02 PM","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"здрасти","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Stoyan Tanev","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Apr 16th at 2:04:46 PM","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:04 PM","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Здравей","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Apr 16th at 2:08:12 PM","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:08 PM","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"проблемът от вчера се оказа козметичен","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Apr 16th at 2:08:18 PM","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:08","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"все пак го има","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Apr 16th at 2:08:57 PM","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:08","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"говорих със integration-app и ще видим дали си го оправят те или пак при нас","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXCheckBox","text":"1 reaction, react with white check mark emoji","depth":24,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Add reaction…","depth":24,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Apr 16th at 2:09:18 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:09","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":false,"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":false,"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":false,"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":false,"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":"Apr 16th at 2:09:44 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:09","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ръчно го смених в база social account на connected","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":false,"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":false,"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":false,"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":"Apr 16th at 2:09:51 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:09","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":false,"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":false,"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":false,"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":false,"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":"Apr 16th at 2:10:15 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:10","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":false,"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":false,"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":false,"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":false,"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":"Apr 16th at 2:10: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:10","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"само да го имаш предвид ако се появи нещо междувременно","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"1 reaction, react with raised hands emoji","depth":24,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Add reaction…","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":false,"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":false,"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":false,"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":"Stoyan Tanev","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 16th at 2:10:36 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:10 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":false,"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":false,"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":false,"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":false,"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":"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":"AXStaticText","text":"Saved for later • Due < 1 minute ago","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Stoyan Tanev","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 29th at 1:02:14 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:02 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Здрасти, за този тикет:","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/SRD-6793","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/SRD-6793","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Jira Cloud","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"Jira Cloud Bug SRD-6793 Les Mills activity types not pulling in Bug SRD-6793 in Jira Cloud Preview in Slack Status Closed Assignee Stoyan Tanev As of Wednesday at 1:02 PM Refresh Open in Jira ✨ Summarise","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Les Mills activity types not pulling in","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Bug SRD-6793 in Jira Cloud","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Status","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Closed","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Assignee","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"As of Wednesday at 1:02 PM","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Refresh","depth":27,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open in Jira","depth":27,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"✨ Summarise","depth":27,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Open in browser","depth":26,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Open","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Share Bug SRD-6793","depth":26,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View conversations","depth":26,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More actions","depth":26,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"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":"Remove from 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":"Apr 29th at 1:02:45 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:02","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":false,"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":false,"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":false,"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":false,"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":"Apr 29th at 1:02:53 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:02","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":false,"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":false,"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":false,"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":false,"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":"Channel","depth":11,"on_screen":true,"role_description":"text"}]...
|
-8095015545399178329
|
-1425365564946724770
|
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
All, 3 unread
DMs
Add new tab
Reminder
DM
Reschedule
Mark as unread
Clear
More actions
Stoyan Tanev:
Здрасти, за този тикет:
[URL_WITH_CREDENTIALS] Ivanov
@Nikolay Ivanov
transitioned a Bug you are watching from
Code Review
⟶
Deployed
…
Wednesday, April 29th
Aneliya Angelova
Aneliya Angelova, Nikolay Yankov, Steliyan Georgiev
Apr 29th
да
Stoyan Tanev
DM
Apr 29th
трябва ли да синкваме нещо от наша страна?
Tuesday, April 28th
Stefka Stoyanova
Thread
Apr 28th
тия тикети е добре да влезнат в другия спринт ли? сложете някакви естимейти тогава
Ves
Thread in
DM
:
исках да те питам credentials на AWS. Направих server на постмарк за QAI но не знам как да добавя key, май вече не е през env. Има ли някакви инструкции?
Apr 28th
смени го в Circle CI env на новия токен който си направил
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Stoyan Tanev
Apr 15th at 1:34:21 PM
1:34 PM
Да пускам го
Jump to date
Lukas Kovalik
Apr 16th at 2:02:18 PM
2:02 PM
здрасти
Stoyan Tanev
Apr 16th at 2:04:46 PM
2:04 PM
Здравей
Lukas Kovalik
Apr 16th at 2:08:12 PM
2:08 PM
проблемът от вчера се оказа козметичен
Apr 16th at 2:08:18 PM
2:08
все пак го има
Apr 16th at 2:08:57 PM
2:08
говорих със integration-app и ще видим дали си го оправят те или пак при нас
1 reaction, react with white check mark emoji
1
Add reaction…
Apr 16th at 2:09:18 PM
2:09
интеграция работи само не ни казват че е минало успешно
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 16th at 2:09:44 PM
2:09
ръчно го смених в база social account на connected
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 16th at 2:09:51 PM
2:09
и си работи всичко
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 16th at 2:10:15 PM
2:10
просто всеки път трябва да се смени на ръка преди да го фикснем
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 16th at 2:10:35 PM
2:10
само да го имаш предвид ако се появи нещо междувременно
1 reaction, react with raised hands emoji
1
Add reaction…
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Stoyan Tanev
Apr 16th at 2:10:36 PM
2:10 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
Jump to date
Saved for later • Due < 1 minute ago
Stoyan Tanev
Apr 29th at 1:02:14 PM
1:02 PM
Здрасти, за този тикет:
https://jiminny.atlassian.net/browse/SRD-6793
https://jiminny.atlassian.net/browse/SRD-6793
Jira Cloud
Jira Cloud
Jira Cloud Bug SRD-6793 Les Mills activity types not pulling in Bug SRD-6793 in Jira Cloud Preview in Slack Status Closed Assignee Stoyan Tanev As of Wednesday at 1:02 PM Refresh Open in Jira ✨ Summarise
Les Mills activity types not pulling in
Bug SRD-6793 in Jira Cloud
Preview in Slack
Status
Closed
Assignee
Stoyan Tanev
As of Wednesday at 1:02 PM
Refresh
Open in Jira
✨ Summarise
Open in browser
Open
Share Bug SRD-6793
View conversations
More actions
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Remove from Later
More actions
Apr 29th at 1:02:45 PM
1:02
Клиента твърди, че са направили нужните промени, но пак не пускаме активити типа в сф
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 29th at 1:02:53 PM
1:02
трябва ли да синкваме нещо от наша страна?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Channel
PhpStormFileEditViewNavigateCodeLaravelRefactorRunToolsGitWindowHelp> 0(ahlSupport Daily - in 2h 59 mAPROD (ssh)DOCKER081DEV (-zsh)₴2APP (-zsh)*3-zsh• ₴4X t1DOCKER (-zsh)Last login: Thu May 7 09:29:14 on consoleX 12PROD (ssh)Run 'do-release-upgrade' to upgrade to it.Poetry could not find a pyproject.toml file in /Users/lukas/jiminny/infrastructure/dev/docker or its parentsDPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/infrastructure/dev/docker or its parentsukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/infrastructure/dev/docker (develop) $100% <78Thu 7 May 12:01:20181screenpipe"• *5PROD*** System restart required ***Last login: Mon Apr 27 07:45:27 2026 from 212.5.153.87lukas@jiminny-prod-bastion:~$ 0X L3 EU (-zsh)Last login: Thu May 7 09:29:14 on consolePoetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.toml file in /Users/lukas or its parents@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ I|X T4 STAGE (-zsh)Last login: Thu May 7 09:29:14 on consolePoetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.toml file in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny$X T5QA (-zsh)Last login: Thu May 7 09:44:56on ttys002Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.tomlfile in /Users/lukas or its parentsX T6 FE (-zsh)Last login: Thu May 7 09:44:56 on ttys004Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.tomlfile in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ DX 17 EXT(-zsh)Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.tomlfile in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ I|STAGEFRONTENDEXTENSION...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
1600
|
64
|
26
|
2026-05-07T09:01:23.662262+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778144483662_m2.jpg...
|
Slack
|
Stoyan Tanev (DM) - Jiminny Inc - 4 new items - Sl Stoyan Tanev (DM) - Jiminny Inc - 4 new items - Slack...
|
True
|
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
All, 3 unread
DMs
Add new tab
Reminder
DM
Reschedule
Mark as unread
Clear
More actions
Stoyan Tanev:
Здрасти, за този тикет:
[URL_WITH_CREDENTIALS] Ivanov
@Nikolay Ivanov
transitioned a Bug you are watching from
Code Review
⟶
Deployed
…
Wednesday, April 29th
Aneliya Angelova
Aneliya Angelova, Nikolay Yankov, Steliyan Georgiev
Apr 29th
да
Stoyan Tanev
DM
Apr 29th
трябва ли да синкваме нещо от наша страна?
Tuesday, April 28th
Stefka Stoyanova
Thread
Apr 28th
тия тикети е добре да влезнат в другия спринт ли? сложете някакви естимейти тогава
Ves
Thread in
DM
:
исках да те питам credentials на AWS. Направих server на постмарк за QAI но не знам как да добавя key, май вече не е през env. Има ли някакви инструкции?
Apr 28th
смени го в Circle CI env на новия токен който си направил
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Stoyan Tanev
Apr 15th at 1:34:21 PM
1:34 PM
Да пускам го
Jump to date
Lukas Kovalik
Apr 16th at 2:02:18 PM
2:02 PM
здрасти
Stoyan Tanev
Apr 16th at 2:04:46 PM
2:04 PM
Здравей
Lukas Kovalik
Apr 16th at 2:08:12 PM
2:08 PM
проблемът от вчера се оказа козметичен
Apr 16th at 2:08:18 PM
2:08
все пак го има
Apr 16th at 2:08:57 PM
2:08
говорих със integration-app и ще видим дали си го оправят те или пак при нас
1 reaction, react with white check mark emoji
1
Add reaction…
Apr 16th at 2:09:18 PM
2:09
интеграция работи само не ни казват че е минало успешно
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 16th at 2:09:44 PM
2:09
ръчно го смених в база social account на connected
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 16th at 2:09:51 PM
2:09
и си работи всичко
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 16th at 2:10:15 PM
2:10
просто всеки път трябва да се смени на ръка преди да го фикснем
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 16th at 2:10:35 PM
2:10
само да го имаш предвид ако се появи нещо междувременно
1 reaction, react with raised hands emoji
1
Add reaction…
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Stoyan Tanev
Apr 16th at 2:10:36 PM
2:10 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
Jump to date
Saved for later • Due < 1 minute ago
Stoyan Tanev
Apr 29th at 1:02:14 PM
1:02 PM
Здрасти, за този тикет:
https://jiminny.atlassian.net/browse/SRD-6793
https://jiminny.atlassian.net/browse/SRD-6793
Jira Cloud
Jira Cloud
Jira Cloud Bug SRD-6793 Les Mills activity types not pulling in Bug SRD-6793 in Jira Cloud Preview in Slack Status Closed Assignee Stoyan Tanev As of Wednesday at 1:02 PM Refresh Open in Jira ✨ Summarise
Les Mills activity types not pulling in
Bug SRD-6793 in Jira Cloud
Preview in Slack
Status
Closed
Assignee
Stoyan Tanev
As of Wednesday at 1:02 PM
Refresh
Open in Jira
✨ Summarise
Open in browser
Open
Share Bug SRD-6793
View conversations
More actions
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Remove from Later
More actions
Apr 29th at 1:02:45 PM
1:02
Клиента твърди, че са направили нужните промени, но пак не пускаме активити типа в сф
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 29th at 1:02:53 PM
1:02
трябва ли да синкваме нещо от наша страна?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Channel...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.0056515955,"top":0.058260176,"width":0.011968086,"height":0.028731046},"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.0029920214,"top":0.10055866,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"bounds":{"left":0.0066489363,"top":0.13806863,"width":0.009973404,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.0029920214,"top":0.15482841,"width":0.017287234,"height":0.054269753},"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.0076462766,"top":0.19233839,"width":0.007978723,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.0029920214,"top":0.20909816,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"bounds":{"left":0.004986702,"top":0.24660814,"width":0.012965426,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.005319149,"top":0.24660814,"width":0.0026595744,"height":0.011173184}},{"char_start":1,"char_count":7,"bounds":{"left":0.0076462766,"top":0.24660814,"width":0.010638298,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.0029920214,"top":0.26336792,"width":0.017287234,"height":0.054269753},"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.0076462766,"top":0.3008779,"width":0.0076462766,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.007978723,"top":0.3008779,"width":0.0019946808,"height":0.011173184}},{"char_start":1,"char_count":4,"bounds":{"left":0.009973404,"top":0.3008779,"width":0.0056515955,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.0029920214,"top":0.31763768,"width":0.017287234,"height":0.054269753},"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.00731383,"top":0.35514766,"width":0.008643617,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.00731383,"top":0.35514766,"width":0.0019946808,"height":0.011173184}},{"char_start":1,"char_count":4,"bounds":{"left":0.00930851,"top":0.35514766,"width":0.0066489363,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.0029920214,"top":0.3719074,"width":0.017287234,"height":0.054269753},"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.006981383,"top":0.4094174,"width":0.008976064,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.00731383,"top":0.4094174,"width":0.0033244682,"height":0.011173184}},{"char_start":1,"char_count":3,"bounds":{"left":0.010638298,"top":0.4094174,"width":0.0056515955,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"All, 3 unread","depth":19,"bounds":{"left":0.028922873,"top":0.09497207,"width":0.021276595,"height":0.026336791},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXRadioButton","text":"DMs","depth":19,"bounds":{"left":0.050199468,"top":0.09497207,"width":0.01462766,"height":0.026336791},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Add new tab","depth":20,"bounds":{"left":0.0674867,"top":0.09497207,"width":0.005319149,"height":0.026336791},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Reminder","depth":22,"bounds":{"left":0.047872342,"top":0.18276137,"width":0.020944148,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.047872342,"top":0.18276137,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":7,"bounds":{"left":0.05086436,"top":0.18276137,"width":0.017952127,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"DM","depth":22,"bounds":{"left":0.047872342,"top":0.19952115,"width":0.00731383,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Reschedule","depth":23,"bounds":{"left":0.0774601,"top":0.17797287,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Mark as unread","depth":23,"bounds":{"left":0.08809841,"top":0.17797287,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Clear","depth":23,"bounds":{"left":0.0987367,"top":0.17797287,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":23,"bounds":{"left":0.109375,"top":0.17797287,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Stoyan Tanev:","depth":23,"bounds":{"left":0.03324468,"top":0.21787709,"width":0.03125,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03324468,"top":0.21787709,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":12,"bounds":{"left":0.035904255,"top":0.21787709,"width":0.027593086,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Здрасти, за този тикет:","depth":23,"bounds":{"left":0.064494684,"top":0.21787709,"width":0.05319149,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.064494684,"top":0.21787709,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":22,"bounds":{"left":0.06715426,"top":0.21787709,"width":0.050531916,"height":0.014365523}}],"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/SRD-6793","depth":23,"bounds":{"left":0.03324468,"top":0.23543495,"width":0.08577128,"height":0.031923383},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/SRD-6793","depth":24,"bounds":{"left":0.03324468,"top":0.23543495,"width":0.08577128,"height":0.031923383},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03324468,"top":0.23543495,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":44,"bounds":{"left":0.03324468,"top":0.23543495,"width":0.08610372,"height":0.031923383}}],"role_description":"text"},{"role":"AXButton","text":"Mark complete","depth":23,"bounds":{"left":0.03324468,"top":0.2434158,"width":0.04255319,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Reminder","depth":22,"bounds":{"left":0.047872342,"top":0.29449323,"width":0.021609042,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.047872342,"top":0.29449323,"width":0.0033244682,"height":0.014365523}},{"char_start":1,"char_count":7,"bounds":{"left":0.05119681,"top":0.29449323,"width":0.018284574,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Post in","depth":22,"bounds":{"left":0.047872342,"top":0.31125298,"width":0.013297873,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.047872342,"top":0.31125298,"width":0.0026595744,"height":0.012769354}},{"char_start":1,"char_count":6,"bounds":{"left":0.050531916,"top":0.31125298,"width":0.010638298,"height":0.012769354}}],"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":22,"bounds":{"left":0.062832445,"top":0.32881084,"width":0.00831117,"height":0.02952913},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.06781915,"top":0.3120511,"width":0.0023271276,"height":0.011173184}},{"char_start":1,"char_count":6,"bounds":{"left":0.0631649,"top":0.32960895,"width":0.00831117,"height":0.028731046}}],"role_description":"text"},{"role":"AXStaticText","text":"Incomplete","depth":22,"bounds":{"left":0.073803194,"top":0.29688746,"width":0.019614361,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.07413564,"top":0.29688746,"width":0.0013297872,"height":0.011971269}},{"char_start":1,"char_count":9,"bounds":{"left":0.07513298,"top":0.29688746,"width":0.01861702,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"Just now","depth":22,"bounds":{"left":0.102726065,"top":0.29608938,"width":0.017287234,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.102726065,"top":0.29608938,"width":0.0019946808,"height":0.013567438}},{"char_start":1,"char_count":7,"bounds":{"left":0.10472074,"top":0.29608938,"width":0.015292553,"height":0.013567438}}],"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov:","depth":23,"bounds":{"left":0.03324468,"top":0.32960895,"width":0.034574468,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03324468,"top":0.32960895,"width":0.0039893617,"height":0.014365523}},{"char_start":1,"char_count":14,"bounds":{"left":0.03723404,"top":0.32960895,"width":0.02925532,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"For those using","depth":23,"bounds":{"left":0.0674867,"top":0.32960895,"width":0.034906916,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.06781915,"top":0.32960895,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":14,"bounds":{"left":0.07047872,"top":0.32960895,"width":0.030917553,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"make cs-fix","depth":24,"bounds":{"left":0.03324468,"top":0.32960895,"width":0.08610372,"height":0.031923383},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"and getting annoyed by how long it takes (since it scans the entire project), you can now use","depth":23,"bounds":{"left":0.03324468,"top":0.3471668,"width":0.08577128,"height":0.040702313},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.04654255,"top":0.3471668,"width":0.0016622341,"height":0.014365523}},{"char_start":1,"char_count":92,"bounds":{"left":0.03324468,"top":0.3471668,"width":0.08577128,"height":0.049481247}}],"role_description":"text"},{"role":"AXStaticText","text":"make cs-fix-branch","depth":24,"bounds":{"left":0.03324468,"top":0.38467678,"width":0.08510638,"height":0.0031923384},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":". It will fix only the files that differ from","depth":23,"bounds":{"left":0.03324468,"top":0.38707104,"width":0.08643617,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"master","depth":24,"bounds":{"left":0.039893616,"top":0.38707104,"width":0.014295213,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":", and it runs in just a couple of seconds","depth":23,"bounds":{"left":0.03324468,"top":0.38707104,"width":0.08610372,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Mark complete","depth":23,"bounds":{"left":0.03324468,"top":0.35514766,"width":0.04255319,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Toast","depth":22,"bounds":{"left":0.047872342,"top":0.40622506,"width":0.011635638,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.047872342,"top":0.40622506,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":4,"bounds":{"left":0.050199468,"top":0.40622506,"width":0.00930851,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"App","depth":22,"bounds":{"left":0.047872342,"top":0.42298484,"width":0.0076462766,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.047872342,"top":0.42298484,"width":0.0029920214,"height":0.012769354}},{"char_start":1,"char_count":2,"bounds":{"left":0.05086436,"top":0.42298484,"width":0.004986702,"height":0.012769354}}],"role_description":"text"},{"role":"AXStaticText","text":"10:00 AM","depth":22,"bounds":{"left":0.10073138,"top":0.40782124,"width":0.019281914,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10106383,"top":0.40782124,"width":0.0026595744,"height":0.012769354}},{"char_start":1,"char_count":7,"bounds":{"left":0.103390954,"top":0.40782124,"width":0.01662234,"height":0.012769354}}],"role_description":"text"},{"role":"AXStaticText","text":"[no preview available]","depth":23,"bounds":{"left":0.03324468,"top":0.44134077,"width":0.04720745,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.03324468,"top":0.44134077,"width":0.0013297872,"height":0.014365523}},{"char_start":1,"char_count":21,"bounds":{"left":0.034574468,"top":0.44134077,"width":0.045877658,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Monday, May 4th","depth":21,"bounds":{"left":0.059507977,"top":0.49481246,"width":0.033909574,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.059840426,"top":0.49561054,"width":0.0039893617,"height":0.012769354}},{"char_start":1,"char_count":14,"bounds":{"left":0.06382979,"top":0.49561054,"width":0.029587766,"height":0.012769354}}],"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":22,"bounds":{"left":0.047872342,"top":0.5403033,"width":0.021609042,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.047872342,"top":0.5403033,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":9,"bounds":{"left":0.049867023,"top":0.5403033,"width":0.019946808,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"App","depth":22,"bounds":{"left":0.047872342,"top":0.55706304,"width":0.0076462766,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.047872342,"top":0.55706304,"width":0.0029920214,"height":0.012769354}},{"char_start":1,"char_count":2,"bounds":{"left":0.05086436,"top":0.55706304,"width":0.004986702,"height":0.012769354}}],"role_description":"text"},{"role":"AXStaticText","text":"Monday","depth":22,"bounds":{"left":0.1043883,"top":0.54189944,"width":0.015625,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.1043883,"top":0.54189944,"width":0.0043218085,"height":0.012769354}},{"char_start":1,"char_count":5,"bounds":{"left":0.10837766,"top":0.54189944,"width":0.011968086,"height":0.012769354}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.04055851,"top":0.575419,"width":0.0013297872,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"@Nikolay Ivanov","depth":23,"bounds":{"left":0.04155585,"top":0.5746209,"width":0.03856383,"height":0.015961692},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"@Nikolay Ivanov","depth":24,"bounds":{"left":0.042220745,"top":0.575419,"width":0.03723404,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.04255319,"top":0.575419,"width":0.0043218085,"height":0.014365523}},{"char_start":1,"char_count":14,"bounds":{"left":0.04654255,"top":0.575419,"width":0.032912236,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"transitioned a Bug you are watching from","depth":23,"bounds":{"left":0.03324468,"top":0.575419,"width":0.07978723,"height":0.031923383},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.080119684,"top":0.575419,"width":0.0013297872,"height":0.014365523}},{"char_start":1,"char_count":39,"bounds":{"left":0.03324468,"top":0.575419,"width":0.080119684,"height":0.031923383}}],"role_description":"text"},{"role":"AXStaticText","text":"Code Review","depth":23,"bounds":{"left":0.03324468,"top":0.59297687,"width":0.07712766,"height":0.031923383},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.09375,"top":0.59297687,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":10,"bounds":{"left":0.03324468,"top":0.59297687,"width":0.0774601,"height":0.031923383}}],"role_description":"text"},{"role":"AXStaticText","text":"⟶","depth":23,"bounds":{"left":0.04920213,"top":0.6105347,"width":0.007978723,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Deployed","depth":23,"bounds":{"left":0.056848403,"top":0.6105347,"width":0.021609042,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.05718085,"top":0.6105347,"width":0.0039893617,"height":0.014365523}},{"char_start":1,"char_count":7,"bounds":{"left":0.060837764,"top":0.6105347,"width":0.01761968,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"…","depth":23,"bounds":{"left":0.078125,"top":0.6105347,"width":0.0039893617,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Wednesday, April 29th","depth":21,"bounds":{"left":0.054521278,"top":0.64644855,"width":0.043882977,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.054853722,"top":0.6472466,"width":0.0043218085,"height":0.012769354}},{"char_start":1,"char_count":20,"bounds":{"left":0.059175532,"top":0.6472466,"width":0.03956117,"height":0.012769354}}],"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":22,"bounds":{"left":0.047872342,"top":0.69193935,"width":0.03756649,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.047872342,"top":0.69193935,"width":0.0033244682,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.05119681,"top":0.69193935,"width":0.034242023,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova, Nikolay Yankov, Steliyan Georgiev","depth":22,"bounds":{"left":0.04920213,"top":0.70790106,"width":0.05086436,"height":0.0015961692},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Apr 29th","depth":22,"bounds":{"left":0.10305851,"top":0.6935355,"width":0.016954787,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10305851,"top":0.6935355,"width":0.0033244682,"height":0.012769354}},{"char_start":1,"char_count":7,"bounds":{"left":0.10605053,"top":0.6935355,"width":0.014295213,"height":0.012769354}}],"role_description":"text"},{"role":"AXStaticText","text":"да","depth":23,"bounds":{"left":0.03324468,"top":0.7086991,"width":0.0056515955,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":22,"bounds":{"left":0.047872342,"top":0.7086991,"width":0.028922873,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"DM","depth":22,"bounds":{"left":0.047872342,"top":0.7086991,"width":0.00731383,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Apr 29th","depth":22,"bounds":{"left":0.10305851,"top":0.7086991,"width":0.016954787,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"трябва ли да синкваме нещо от наша страна?","depth":23,"bounds":{"left":0.03324468,"top":0.7086991,"width":0.07413564,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Tuesday, April 28th","depth":21,"bounds":{"left":0.05817819,"top":0.7086991,"width":0.036901597,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":22,"bounds":{"left":0.047872342,"top":0.7086991,"width":0.03756649,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Thread","depth":22,"bounds":{"left":0.047872342,"top":0.7086991,"width":0.013297873,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Apr 28th","depth":22,"bounds":{"left":0.10305851,"top":0.7086991,"width":0.016954787,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"тия тикети е добре да влезнат в другия спринт ли? сложете някакви естимейти тогава","depth":23,"bounds":{"left":0.03324468,"top":0.7086991,"width":0.08643617,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Ves","depth":22,"bounds":{"left":0.047872342,"top":0.7086991,"width":0.0076462766,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Thread in","depth":22,"bounds":{"left":0.047872342,"top":0.7086991,"width":0.017952127,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.06549202,"top":0.7086991,"width":0.0013297872,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"DM","depth":22,"bounds":{"left":0.06648936,"top":0.7086991,"width":0.0076462766,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":":","depth":22,"bounds":{"left":0.073803194,"top":0.7086991,"width":0.0023271276,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"исках да те питам credentials на AWS. Направих server на постмарк за QAI но не знам как да добавя key, май вече не е през env. Има ли някакви инструкции?","depth":22,"bounds":{"left":0.047872342,"top":0.7086991,"width":0.05418883,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Apr 28th","depth":22,"bounds":{"left":0.10305851,"top":0.7086991,"width":0.016954787,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"смени го в Circle CI env на новия токен който си направил","depth":23,"bounds":{"left":0.03324468,"top":0.7086991,"width":0.075465426,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.13530585,"top":0.09177973,"width":0.030585106,"height":0.030327214},"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.14461437,"top":0.10055866,"width":0.01861702,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.14461437,"top":0.10055866,"width":0.0039893617,"height":0.012769354}},{"char_start":1,"char_count":7,"bounds":{"left":0.14860372,"top":0.10055866,"width":0.014960106,"height":0.012769354}}],"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"bounds":{"left":0.16722074,"top":0.09177973,"width":0.033909574,"height":0.030327214},"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.17652926,"top":0.10055866,"width":0.021941489,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.17652926,"top":0.10055866,"width":0.0033244682,"height":0.012769354}},{"char_start":1,"char_count":9,"bounds":{"left":0.17952128,"top":0.10055866,"width":0.019281914,"height":0.012769354}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.20246011,"top":0.09177973,"width":0.020944148,"height":0.030327214},"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.21176861,"top":0.10055866,"width":0.008976064,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.21176861,"top":0.10055866,"width":0.0026595744,"height":0.012769354}},{"char_start":1,"char_count":4,"bounds":{"left":0.21442819,"top":0.10055866,"width":0.0063164895,"height":0.012769354}}],"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.2244016,"top":0.09177973,"width":0.010970744,"height":0.030327214},"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,"bounds":{"left":0.12965426,"top":0.0518755,"width":0.015625,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"bounds":{"left":0.12965426,"top":0.0518755,"width":0.0076462766,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"bounds":{"left":0.12965426,"top":0.0518755,"width":0.013962766,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Stoyan Tanev","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Apr 15th at 1:34:21 PM","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:34 PM","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Да пускам го","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.2523271,"top":0.12689546,"width":0.05285904,"height":0.022346368},"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":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Apr 16th at 2:02:18 PM","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:02 PM","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"здрасти","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Stoyan Tanev","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Apr 16th at 2:04:46 PM","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:04 PM","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Здравей","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Apr 16th at 2:08:12 PM","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:08 PM","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"проблемът от вчера се оказа козметичен","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Apr 16th at 2:08:18 PM","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:08","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"все пак го има","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Apr 16th at 2:08:57 PM","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:08","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"говорих със integration-app и ще видим дали си го оправят те или пак при нас","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXCheckBox","text":"1 reaction, react with white check mark emoji","depth":24,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Add reaction…","depth":24,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Apr 16th at 2:09:18 PM","depth":24,"bounds":{"left":0.140625,"top":0.12849163,"width":0.007978723,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:09","depth":25,"bounds":{"left":0.140625,"top":0.12849163,"width":0.007978723,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.140625,"top":0.12849163,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":3,"bounds":{"left":0.14295213,"top":0.12849163,"width":0.005984043,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"интеграция работи само не ни казват че е минало успешно","depth":24,"bounds":{"left":0.1512633,"top":0.12609737,"width":0.13663563,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.1512633,"top":0.12609737,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":54,"bounds":{"left":0.15425532,"top":0.12609737,"width":0.13364361,"height":0.014365523}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":false,"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":false,"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":false,"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":"Apr 16th at 2:09:44 PM","depth":24,"bounds":{"left":0.140625,"top":0.15243416,"width":0.007978723,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:09","depth":25,"bounds":{"left":0.140625,"top":0.15243416,"width":0.007978723,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.140625,"top":0.15243416,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":3,"bounds":{"left":0.14295213,"top":0.15243416,"width":0.005984043,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"ръчно го смених в база social account на connected","depth":24,"bounds":{"left":0.1512633,"top":0.15003991,"width":0.11569149,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.1512633,"top":0.15003991,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":49,"bounds":{"left":0.15392287,"top":0.15003991,"width":0.11303192,"height":0.014365523}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":false,"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":false,"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":false,"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":"Apr 16th at 2:09:51 PM","depth":24,"bounds":{"left":0.140625,"top":0.1763767,"width":0.007978723,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:09","depth":25,"bounds":{"left":0.140625,"top":0.1763767,"width":0.007978723,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.140625,"top":0.1763767,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":3,"bounds":{"left":0.14295213,"top":0.1763767,"width":0.005984043,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"и си работи всичко","depth":24,"bounds":{"left":0.1512633,"top":0.17398244,"width":0.043882977,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.1512633,"top":0.17398244,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":17,"bounds":{"left":0.15425532,"top":0.17398244,"width":0.04089096,"height":0.014365523}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":false,"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":false,"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":false,"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":"Apr 16th at 2:10:15 PM","depth":24,"bounds":{"left":0.140625,"top":0.20031923,"width":0.007978723,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:10","depth":25,"bounds":{"left":0.140625,"top":0.20031923,"width":0.007978723,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.140625,"top":0.20031923,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":3,"bounds":{"left":0.14295213,"top":0.20031923,"width":0.005984043,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"просто всеки път трябва да се смени на ръка преди да го фикснем","depth":24,"bounds":{"left":0.1512633,"top":0.19792499,"width":0.15325798,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.1512633,"top":0.19792499,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":62,"bounds":{"left":0.15425532,"top":0.19792499,"width":0.15026596,"height":0.014365523}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":false,"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":false,"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":false,"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":"Apr 16th at 2:10:35 PM","depth":24,"bounds":{"left":0.140625,"top":0.22426178,"width":0.007978723,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:10","depth":25,"bounds":{"left":0.140625,"top":0.22426178,"width":0.007978723,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"само да го имаш предвид ако се появи нещо междувременно","depth":24,"bounds":{"left":0.1512633,"top":0.22186752,"width":0.14261968,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"1 reaction, react with raised hands emoji","depth":24,"bounds":{"left":0.1512633,"top":0.24102154,"width":0.014295213,"height":0.01915403},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":25,"bounds":{"left":0.16057181,"top":0.2442139,"width":0.0023271276,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Add reaction…","depth":24,"bounds":{"left":0.16655585,"top":0.24102154,"width":0.011635638,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":false,"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":false,"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":false,"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":"Stoyan Tanev","depth":23,"bounds":{"left":0.1512633,"top":0.2697526,"width":0.029587766,"height":0.017557861},"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.1875,"top":0.27134877,"width":0.0026595744,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 16th at 2:10:36 PM","depth":23,"bounds":{"left":0.18982713,"top":0.273743,"width":0.015292553,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:10 PM","depth":24,"bounds":{"left":0.18982713,"top":0.273743,"width":0.015292553,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Ясно, добре ще го имам в предвид","depth":24,"bounds":{"left":0.1512633,"top":0.28890663,"width":0.08045213,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":false,"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":false,"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":false,"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":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.25,"top":0.31923383,"width":0.057513297,"height":0.022346368},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Saved for later • Due < 1 minute ago","depth":23,"bounds":{"left":0.1512633,"top":0.35115722,"width":0.06981383,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Stoyan Tanev","depth":23,"bounds":{"left":0.1512633,"top":0.36552274,"width":0.029587766,"height":0.017557861},"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.1875,"top":0.36711892,"width":0.0026595744,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 29th at 1:02:14 PM","depth":23,"bounds":{"left":0.18982713,"top":0.36951315,"width":0.015292553,"height":0.011971269},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:02 PM","depth":24,"bounds":{"left":0.18982713,"top":0.36951315,"width":0.015292553,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Здрасти, за този тикет:","depth":24,"bounds":{"left":0.1512633,"top":0.38467678,"width":0.054521278,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/SRD-6793","depth":24,"bounds":{"left":0.20545213,"top":0.38467678,"width":0.103390954,"height":0.014365523},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/SRD-6793","depth":25,"bounds":{"left":0.20545213,"top":0.38467678,"width":0.103390954,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.1512633,"top":0.40782124,"width":0.018949468,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Jira Cloud","depth":23,"bounds":{"left":0.17121011,"top":0.40782124,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"Jira Cloud Bug SRD-6793 Les Mills activity types not pulling in Bug SRD-6793 in Jira Cloud Preview in Slack Status Closed Assignee Stoyan Tanev As of Wednesday at 1:02 PM Refresh Open in Jira ✨ Summarise","depth":25,"bounds":{"left":0.1512633,"top":0.424581,"width":0.15957446,"height":0.1348763},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Les Mills activity types not pulling in","depth":26,"bounds":{"left":0.17154256,"top":0.43814844,"width":0.080119684,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Bug SRD-6793 in Jira Cloud","depth":27,"bounds":{"left":0.17154256,"top":0.45411015,"width":0.05319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"bounds":{"left":0.17154256,"top":0.45411015,"width":0.03125,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Status","depth":26,"bounds":{"left":0.17154256,"top":0.4772546,"width":0.011635638,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Closed","depth":26,"bounds":{"left":0.17287233,"top":0.4964086,"width":0.014960106,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Assignee","depth":26,"bounds":{"left":0.19680852,"top":0.4772546,"width":0.017287234,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":27,"bounds":{"left":0.20711437,"top":0.49720672,"width":0.025598405,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"As of Wednesday at 1:02 PM","depth":27,"bounds":{"left":0.15558511,"top":0.53471667,"width":0.05518617,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Refresh","depth":27,"bounds":{"left":0.21176861,"top":0.53790903,"width":0.01462766,"height":0.006384677},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open in Jira","depth":27,"bounds":{"left":0.24035904,"top":0.52992815,"width":0.03125,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"✨ Summarise","depth":27,"bounds":{"left":0.27260637,"top":0.52992815,"width":0.03523936,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Open in browser","depth":26,"bounds":{"left":0.24734043,"top":0.43814844,"width":0.022938829,"height":0.025538707},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Open","depth":27,"bounds":{"left":0.25664893,"top":0.44373503,"width":0.010970744,"height":0.013567438},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Share Bug SRD-6793","depth":26,"bounds":{"left":0.27327126,"top":0.43814844,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View conversations","depth":26,"bounds":{"left":0.2839096,"top":0.43814844,"width":0.010638298,"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":26,"bounds":{"left":0.2945479,"top":0.43814844,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.33543882,"top":0.33758977,"width":0.010638298,"height":0.025538707},"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.3460771,"top":0.33758977,"width":0.010638298,"height":0.025538707},"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.3567154,"top":0.33758977,"width":0.010638298,"height":0.025538707},"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.36735374,"top":0.33758977,"width":0.010638298,"height":0.025538707},"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,"bounds":{"left":0.37799203,"top":0.33758977,"width":0.010638298,"height":0.025538707},"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,"bounds":{"left":0.38863033,"top":0.33758977,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Remove from Later","depth":25,"bounds":{"left":0.39926863,"top":0.33758977,"width":0.010638298,"height":0.025538707},"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,"bounds":{"left":0.40990692,"top":0.33758977,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Apr 29th at 1:02:45 PM","depth":24,"bounds":{"left":0.140625,"top":0.57302475,"width":0.007978723,"height":0.011971269},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:02","depth":25,"bounds":{"left":0.140625,"top":0.57302475,"width":0.007978723,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Клиента твърди, че са направили нужните промени, но пак не пускаме активити типа в сф","depth":24,"bounds":{"left":0.1512633,"top":0.5706305,"width":0.20910904,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":false,"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":false,"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":false,"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":"Apr 29th at 1:02:53 PM","depth":24,"bounds":{"left":0.140625,"top":0.5969673,"width":0.007978723,"height":0.011971269},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:02","depth":25,"bounds":{"left":0.140625,"top":0.5969673,"width":0.007978723,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"трябва ли да синкваме нещо от наша страна?","depth":24,"bounds":{"left":0.1512633,"top":0.594573,"width":0.10472074,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":false,"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":false,"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":false,"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.13696809,"top":0.6272945,"width":0.2835771,"height":0.030327214},"on_screen":true,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Channel","depth":11,"bounds":{"left":0.0,"top":0.7126895,"width":0.017287234,"height":0.0007980846},"on_screen":true,"role_description":"text"}]...
|
-8095015545399178329
|
-1425365564946724770
|
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
All, 3 unread
DMs
Add new tab
Reminder
DM
Reschedule
Mark as unread
Clear
More actions
Stoyan Tanev:
Здрасти, за този тикет:
[URL_WITH_CREDENTIALS] Ivanov
@Nikolay Ivanov
transitioned a Bug you are watching from
Code Review
⟶
Deployed
…
Wednesday, April 29th
Aneliya Angelova
Aneliya Angelova, Nikolay Yankov, Steliyan Georgiev
Apr 29th
да
Stoyan Tanev
DM
Apr 29th
трябва ли да синкваме нещо от наша страна?
Tuesday, April 28th
Stefka Stoyanova
Thread
Apr 28th
тия тикети е добре да влезнат в другия спринт ли? сложете някакви естимейти тогава
Ves
Thread in
DM
:
исках да те питам credentials на AWS. Направих server на постмарк за QAI но не знам как да добавя key, май вече не е през env. Има ли някакви инструкции?
Apr 28th
смени го в Circle CI env на новия токен който си направил
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Stoyan Tanev
Apr 15th at 1:34:21 PM
1:34 PM
Да пускам го
Jump to date
Lukas Kovalik
Apr 16th at 2:02:18 PM
2:02 PM
здрасти
Stoyan Tanev
Apr 16th at 2:04:46 PM
2:04 PM
Здравей
Lukas Kovalik
Apr 16th at 2:08:12 PM
2:08 PM
проблемът от вчера се оказа козметичен
Apr 16th at 2:08:18 PM
2:08
все пак го има
Apr 16th at 2:08:57 PM
2:08
говорих със integration-app и ще видим дали си го оправят те или пак при нас
1 reaction, react with white check mark emoji
1
Add reaction…
Apr 16th at 2:09:18 PM
2:09
интеграция работи само не ни казват че е минало успешно
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 16th at 2:09:44 PM
2:09
ръчно го смених в база social account на connected
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 16th at 2:09:51 PM
2:09
и си работи всичко
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 16th at 2:10:15 PM
2:10
просто всеки път трябва да се смени на ръка преди да го фикснем
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 16th at 2:10:35 PM
2:10
само да го имаш предвид ако се появи нещо междувременно
1 reaction, react with raised hands emoji
1
Add reaction…
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Stoyan Tanev
Apr 16th at 2:10:36 PM
2:10 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
Jump to date
Saved for later • Due < 1 minute ago
Stoyan Tanev
Apr 29th at 1:02:14 PM
1:02 PM
Здрасти, за този тикет:
https://jiminny.atlassian.net/browse/SRD-6793
https://jiminny.atlassian.net/browse/SRD-6793
Jira Cloud
Jira Cloud
Jira Cloud Bug SRD-6793 Les Mills activity types not pulling in Bug SRD-6793 in Jira Cloud Preview in Slack Status Closed Assignee Stoyan Tanev As of Wednesday at 1:02 PM Refresh Open in Jira ✨ Summarise
Les Mills activity types not pulling in
Bug SRD-6793 in Jira Cloud
Preview in Slack
Status
Closed
Assignee
Stoyan Tanev
As of Wednesday at 1:02 PM
Refresh
Open in Jira
✨ Summarise
Open in browser
Open
Share Bug SRD-6793
View conversations
More actions
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Remove from Later
More actions
Apr 29th at 1:02:45 PM
1:02
Клиента твърди, че са направили нужните промени, но пак не пускаме активити типа в сф
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Apr 29th at 1:02:53 PM
1:02
трябва ли да синкваме нещо от наша страна?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Channel
HomeDMSSlackViewMistonWindowHelpQ Describe what you are looking forAC.MILVAll 3DMskeminderStovan lanev: sлрасти, за този тике...Mark comnleteReminderIncomplete Just nowPost in #...Nikolay Ivanov: For those using make .../ Mark comnlete10:00 AMIÍno preview available'Monday. May 4thLlira Gloud_@Nikolay Ivanov transitioned aBug you are watching from Code …Wednesday, April 29theAneliya AngelovaAor 29thlUseC) ChandeEmailJob.ohoP DeactivateUserJob.php@ DeleteScheduledUcerAc 47(C) Setur DefaultSavedSean© SyncTolntercom.php© SyncToPlanhat.php© SyncToUserPilot.phpC. RaseProceccina.loh.nhnC) Dummv.loh.nhnC ImnortDocallAPocordinas 1© ImportRemoteTrackJob.ph(eulob,php(e) lohdicnatchor nhnStoyan TanevMessagesLo Add canvas(@ Filesинтеграция работи само не ни казват че е м Thursday. April 16th ~рьчно го смених в база social account на connectedи си работи всичкопросто всеки път трябва да се смени на рька преди да го фикснемсамо да го имаш предвид ако се появи нещо междувременноStoyan Tanev 2:10 PMЯсно, добре ще го имам в предвидWednesdav. April 29thvSaved tor ater • Due ‹ 1 minute agoStoyan Tanev 1:02 PMЗлрасти, за този тикет: [URL_WITH_CREDENTIALS] =1$crmObject->value => $this->id,'activity' => $activity-›getIdO,'emitEvent' => $emitEvent,SupdateData =sentityldrield = null.// For leads and opportunities, also nullify the stage idif (Sstageld && in_array(Scrm0biect. [Crm0biect::LEAD. CrmObiect::0PPORTUNITY1..strictfravel.log4 SF jiminny@localhost]A HS_local (jiminny@localhost]suppon Dally• In zn osm100% 12Thu 7 May 12:01:23+0 ..« console [PROD] X« console [EU]dojiminny037 A1 A35 V64 ^652654657 VS team1dSUBSTRING_INDEX(c.calendar_provider_id, '@', -1)) AS calendar_domairu 1<->1..n: ON U.team id = t.iddars c ON c.user_id = u.id AND c.status = 'active' AND c.calendar_provider_id LIKE '%0%'team domains tdteamid = tiodeleted at TS NUlI.domain = LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1)).id, t.name, calendar_domain.name, calendar_domain;rom users u join calendars c 1<->1.n: on c.user_id = u.idamid - 909.om activities where id = 74049485: # team 563 crm 537'om activities where id = 73272382: # team 563 crm 537rom activitles where 10 = 644005897# team 563 crm 537rom activitles where 1d = 58081215: # team 565 crm 557om activities where id = 54520297: # team 563 crm 537om participants where activity id = 58081273:rom activities where erm confiquration 1d = 537 and provider = 'aircaluit 1d = 19003658 order by uodated at desc:rom contacts where erm confiquration 1d = 537 and 1d = 359577591om accounts where erm confiauration 1d e 537 and 1d = 190036581select * from automated_report_results where id = 1976;select * from automated_reports where id = 583;select * from activity_searches where id = 87714;select * from activity search filtens where activity search id = 87714÷SELECT * FROM activities WHERE uuid_to_bin('8827f672-202d-4162-9d04-73ff5f0566a9') = uuidor uuid_to_bin('47842446-af51-4bcb-854f-CC6560290101') = uuid;SELECT * FROM crm confiqurations WHERE provider = 'hubspot':select * from rate limits-Cascade• Hubspot Rate Limit130, 90, t80) vipatr) in 30 minutes and then after 5 request another 990 in 90DO I understand it correctly?Thinkinarate limit and throw an excention. If the exception bubbles uo uncauaht. Laravel marks those attemots as failled and schedules retries usina thebackoff array—30 seconds for the first retry, 90 seconds for the second, 180 seconds for the third. The problem is that after 30 seconds when those900 failed jobs retry, the bucket has cleared but can only accommodate another 100 requests in the next 10-second window, so roughly 800 jobs failagain and get scheduled for the 90-second backoft, creating a cascadina retry pattern that stretches out over several minutes.With only three total attempts allowed, most jobs never succeed-maybe 400 out of 1000 make it through before hitting the retry limit. So catchingthe exception and letting it fail isn't viable. The alternative is to catch the RateLimitException and call release() with a delay calculated from when thebucket will have capacity again, but there's a complication: in Laravel, release) still increments the attempts counter, so you'd burn through yourthree tries just from releasing, not from actual failures. The rate limit window for HubSpot's search endpoint is actually quite short - it resets everysecond or so, meaning after 30 seconds the bucket has cleared many times over. When those 995 rate-limited jobs retry simultaneously after thebackoff period, they'll hit the same bottleneck: only 5 can succeed per second, so the rest get rate-limited again and cycle through the backoffdelavs. The user's mental model assumes all jobs wait together and retry together, but in reality they're competing for the same per-second quotawith each retry attemptAsk anvthina (84L)<> Code Claude Qnus 17 Medium66-52.UTE.8Po. 4 spac...
|
1598
|
NULL
|
NULL
|
NULL
|
|
15069
|
675
|
3
|
2026-05-11T06:14:28.176640+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778480068176_m2.jpg...
|
PhpStorm
|
faVsco.js – CrmObjectsResolver.php
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PnostorimcodeFV faVsco.jsProleteyOooortunitvMatche PnostorimcodeFV faVsco.jsProleteyOooortunitvMatche© HubspotSyncStrategyBase.phpy syneermenttes tralt.onp©poortunitvsvncstCachedcrmservicebecorator.pnp© ProspectCache.php© CheckAndRetryRemoteMatch.phpService Traits@ Client.ohp© MatchActivityCrmData.php© CrmActivityService.phg* RateLimitexception.pngC)DecorateActivitv.on(t DeleteObiectsTrait.class Crmubjectsresolverououc tunction resolverromcall serviceuntertace ScrmService, call cauu: arravA1Av15© FieldDefinitions.php© PayloadBuilder.php© Profile.php© QueryBuilder.php© QueryHandler.phpC) @uerviterator.ong© QueryResults.phpC) Service.php© SyncBatchRedisSerC TraitsSdecorator = resolved nae: Cachedcrmservicedecorator::class)sSdecorator->setCrmServiceScrmService^* Sermibnects =Slead. Saccount. Sooportunatu. Scontact sstadellif u emotv(Scal->aetContactEma1Lo0)^ScrmObjects = Sdecorator->matchExactlyByEmail(Scall->getContactEmailO, Scall->getUserId):basecllent.onp© BaseService.php© CachedCrmServiceDeif (empty($crmObjects) && Scall->get0therPartyPhoneNumberO l== nulb) ‹(c) Countrycodekesolver.Scrmlhiects = Sdeconaton->matchRvPhoneCrmActivityProvideriniScall->get0therPartyPhoneNumberO,.c) Crmactivitvservice.on© CrmConfiqurationSettiliiw?neinie MuintieleteuuScall->getUserIdO(C) crmObiectsResolver.o© DefaultProspectSearclC)EmailHeloer.oho(D FindeProsnertintarfarLocal ChangesConsole,Log xChanaes 12 filedTJ0 + → Side-by-side viewer •Do not ignoreCurrent vercion tests/Unit/Policies/CanAccessAiReporis|est.onpHighlight words? , ?= .env.local app@ Client.oho apn/Services/Crm/Hubspot<?ohp‹› >© HandleHubspotRateLimit.php app/Jobs/Middleware© HubspotClientinterface.php app/Services/Crm/Hubspot© HubspotPaginationService.php app/Services/Crm/Hubspot/Pagination@ JiminnyDebugCommand.php app/Console/Commandsphp logging.php config© MatchActivityCrmData.php app/Jobs/Crm© MatchCrmData.php app/Jobs/Activity/Import© PaginationState.php app/Services/Crm/Hubspot/Pagination© RateLimitException.php app/Exceptions© Service.php app/Services/Crm/HubspotUnversioned Files 9 files=.env.nikilocal appE.env.other app©) CanAccessAiReportsTest.php tests/Unit/Policies© CreateMockAskJiminnvReportResultCommand.php app/Console/Commands/Rer6 favicon.ico publicE ids txt aprdeclare(strict types=1)namespace Tests Unit Policles:use JaminnvcontractsAcu.Permisszonenumuse Jiminny Models. Teamuse Jiminny Models Useruse Jiminny Policies UserPolicv:use Jiminny Repositories\AutomatedReportsRepository:use PlPlni+ Sramework Attrihutes DataProviden:use pHPlni+ Eramewonk Mock0hriect Mock0hiect.use PHPUnit\Framework\TestCase;class CanAccessAiReportsTest extends TestCaseiaraw sol querv sall aool@ SimulateWebhooksCommand.ohn app/Console/Commands/Crm/Hubspotprivate AutomatedReportsRepository&Mock0bject SautomatedReportsRepository:private UserPolicy $policy;4Dally - Platorm • In 31m100% 5• Mon 11 May 9:14:28AskJiminnyReportActivityServiceTest v=laravel.logA SF (jiminny@localhost]4 HS_local [jiminny@localhost]# console [PKob."url":nccos:a.nel.cloudtlare.comredorcV4.S=NYALSVIPorymszorSUnxY24S0ZKh"max_age\":6048005"J,"NEL":["{"success fraction":0.01.26A console [EU]A console [STAGING]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-1.0.107-May-26 14:51:15 GMT: domain=.hubapi.com;: Http0nly: Secure: SameSite=None"]."керогс-10":"1enapolnus".N"report_to\":\"cf-nel\","max ade".604800-""Serven"•["cloudflare"1}} {"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab" ,"trace id"."c7ab8365-903f-46d4-9403-0e5b551e3545"}Cascade0 HubSpot Paginationpreventive rate limit in the client (now we have only reactive for search)I'll start by reading all the relevant files to do a thorough review.Read HubspotPaginationService.php and MatchActivityCrmData.phpkeaа HubspotPaginationservice.ongRead MatchActivityCrmData.phpancthient. pook for potential issues andAsk anything (&AL)+ <> CodeSAdaptive• 0W Windsurf Teams 28-10 LITF.RPo. 4 spaces...
|
NULL
|
-8093965838637206665
|
NULL
|
click
|
ocr
|
NULL
|
PnostorimcodeFV faVsco.jsProleteyOooortunitvMatche PnostorimcodeFV faVsco.jsProleteyOooortunitvMatche© HubspotSyncStrategyBase.phpy syneermenttes tralt.onp©poortunitvsvncstCachedcrmservicebecorator.pnp© ProspectCache.php© CheckAndRetryRemoteMatch.phpService Traits@ Client.ohp© MatchActivityCrmData.php© CrmActivityService.phg* RateLimitexception.pngC)DecorateActivitv.on(t DeleteObiectsTrait.class Crmubjectsresolverououc tunction resolverromcall serviceuntertace ScrmService, call cauu: arravA1Av15© FieldDefinitions.php© PayloadBuilder.php© Profile.php© QueryBuilder.php© QueryHandler.phpC) @uerviterator.ong© QueryResults.phpC) Service.php© SyncBatchRedisSerC TraitsSdecorator = resolved nae: Cachedcrmservicedecorator::class)sSdecorator->setCrmServiceScrmService^* Sermibnects =Slead. Saccount. Sooportunatu. Scontact sstadellif u emotv(Scal->aetContactEma1Lo0)^ScrmObjects = Sdecorator->matchExactlyByEmail(Scall->getContactEmailO, Scall->getUserId):basecllent.onp© BaseService.php© CachedCrmServiceDeif (empty($crmObjects) && Scall->get0therPartyPhoneNumberO l== nulb) ‹(c) Countrycodekesolver.Scrmlhiects = Sdeconaton->matchRvPhoneCrmActivityProvideriniScall->get0therPartyPhoneNumberO,.c) Crmactivitvservice.on© CrmConfiqurationSettiliiw?neinie MuintieleteuuScall->getUserIdO(C) crmObiectsResolver.o© DefaultProspectSearclC)EmailHeloer.oho(D FindeProsnertintarfarLocal ChangesConsole,Log xChanaes 12 filedTJ0 + → Side-by-side viewer •Do not ignoreCurrent vercion tests/Unit/Policies/CanAccessAiReporis|est.onpHighlight words? , ?= .env.local app@ Client.oho apn/Services/Crm/Hubspot<?ohp‹› >© HandleHubspotRateLimit.php app/Jobs/Middleware© HubspotClientinterface.php app/Services/Crm/Hubspot© HubspotPaginationService.php app/Services/Crm/Hubspot/Pagination@ JiminnyDebugCommand.php app/Console/Commandsphp logging.php config© MatchActivityCrmData.php app/Jobs/Crm© MatchCrmData.php app/Jobs/Activity/Import© PaginationState.php app/Services/Crm/Hubspot/Pagination© RateLimitException.php app/Exceptions© Service.php app/Services/Crm/HubspotUnversioned Files 9 files=.env.nikilocal appE.env.other app©) CanAccessAiReportsTest.php tests/Unit/Policies© CreateMockAskJiminnvReportResultCommand.php app/Console/Commands/Rer6 favicon.ico publicE ids txt aprdeclare(strict types=1)namespace Tests Unit Policles:use JaminnvcontractsAcu.Permisszonenumuse Jiminny Models. Teamuse Jiminny Models Useruse Jiminny Policies UserPolicv:use Jiminny Repositories\AutomatedReportsRepository:use PlPlni+ Sramework Attrihutes DataProviden:use pHPlni+ Eramewonk Mock0hriect Mock0hiect.use PHPUnit\Framework\TestCase;class CanAccessAiReportsTest extends TestCaseiaraw sol querv sall aool@ SimulateWebhooksCommand.ohn app/Console/Commands/Crm/Hubspotprivate AutomatedReportsRepository&Mock0bject SautomatedReportsRepository:private UserPolicy $policy;4Dally - Platorm • In 31m100% 5• Mon 11 May 9:14:28AskJiminnyReportActivityServiceTest v=laravel.logA SF (jiminny@localhost]4 HS_local [jiminny@localhost]# console [PKob."url":nccos:a.nel.cloudtlare.comredorcV4.S=NYALSVIPorymszorSUnxY24S0ZKh"max_age\":6048005"J,"NEL":["{"success fraction":0.01.26A console [EU]A console [STAGING]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-1.0.107-May-26 14:51:15 GMT: domain=.hubapi.com;: Http0nly: Secure: SameSite=None"]."керогс-10":"1enapolnus".N"report_to\":\"cf-nel\","max ade".604800-""Serven"•["cloudflare"1}} {"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab" ,"trace id"."c7ab8365-903f-46d4-9403-0e5b551e3545"}Cascade0 HubSpot Paginationpreventive rate limit in the client (now we have only reactive for search)I'll start by reading all the relevant files to do a thorough review.Read HubspotPaginationService.php and MatchActivityCrmData.phpkeaа HubspotPaginationservice.ongRead MatchActivityCrmData.phpancthient. pook for potential issues andAsk anything (&AL)+ <> CodeSAdaptive• 0W Windsurf Teams 28-10 LITF.RPo. 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
24859
|
1040
|
20
|
2026-05-12T10:05:22.330315+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-12/1778 /Users/lukas/.screenpipe/data/data/2026-05-12/1778580322330_m1.jpg...
|
Firefox
|
[JY-20773] User Pilot not receiving events on repo [JY-20773] User Pilot not receiving events on report generated - Jira — Work...
|
True
|
jiminny.atlassian.net/browse/JY-20773
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Unnamed Group
TypeError: League\Flysystem\Filesyst Unnamed Group
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
CloudWatch | us-east-2
CloudWatch | us-east-2
Unnamed Group
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Pull requests · jiminny/app
Pull requests · jiminny/app
[JY-20773] User Pilot not receiving events on report generated - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
Data Explorer
Data Explorer
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
Jiminny
Jiminny
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
[SRD-6793] Les Mills activity types not pulling in - Jira
[SRD-6793] Les Mills activity types not pulling in - Jira
Platform Team - Backlog - Jira
Platform Team - Backlog - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Sidebar
Sidebar
Top Bar
Top Bar
Main Content
Main Content
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent
Starred
Starred
Apps
Apps
More actions for Apps
More actions for Apps
Spaces...
|
[{"role":"AXButton","text" [{"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":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — 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":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | us-east-2","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | us-east-2","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":"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":"AXRadioButton","text":"[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - 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":"[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · 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-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · 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":"Pull requests · 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":"Pull requests · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20773] User Pilot not receiving events on report generated - 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":"[JY-20773] User Pilot not receiving events on report generated - Jira","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":"[JY-20776] Automated report - sentry - 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":"[JY-20776] Automated report - sentry - Jira","depth":5,"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":"AXRadioButton","text":"JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · 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-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Data Explorer","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Data Explorer","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20776] Automated report - sentry - 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":"[JY-20776] Automated report - sentry - Jira","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":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · 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-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6793] Les Mills activity types not pulling in - 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":"[SRD-6793] Les Mills activity types not pulling in - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Team - Backlog - 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 Team - Backlog - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20773] User Pilot not receiving events on report generated - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"[JY-20773] User Pilot not receiving events on report generated - 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":"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,"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,"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,"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,"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,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to:","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sidebar","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sidebar","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Top Bar","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Top Bar","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Main Content","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Main Content","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse sidebar [","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Collapse sidebar [","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Switch sites or apps","depth":10,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Switch sites or apps","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Go to your Jira homepage","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"Search, press enter to navigate to advanced search with your text query","depth":11,"on_screen":true,"help_text":"","placeholder":"Search","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Create","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Rovo Ask Rovo","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Rovo","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Notifications","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notifications","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Help","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Help","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Settings","depth":12,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Settings","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"lukas.kovalik@jiminny.com","depth":12,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"lukas.kovalik@jiminny.com","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"For you","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"For you","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Recent","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":"Recent","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Starred","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":"Starred","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Apps","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":"Apps","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Apps","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Apps","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Spaces","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true}]...
|
-8093836647323524193
|
-3164532848841887584
|
click
|
accessibility
|
NULL
|
Unnamed Group
TypeError: League\Flysystem\Filesyst Unnamed Group
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
CloudWatch | us-east-2
CloudWatch | us-east-2
Unnamed Group
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Pull requests · jiminny/app
Pull requests · jiminny/app
[JY-20773] User Pilot not receiving events on report generated - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
Data Explorer
Data Explorer
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
Jiminny
Jiminny
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
[SRD-6793] Les Mills activity types not pulling in - Jira
[SRD-6793] Les Mills activity types not pulling in - Jira
Platform Team - Backlog - Jira
Platform Team - Backlog - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Sidebar
Sidebar
Top Bar
Top Bar
Main Content
Main Content
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent
Starred
Starred
Apps
Apps
More actions for Apps
More actions for Apps
Spaces...
|
24855
|
NULL
|
NULL
|
NULL
|
|
26114
|
1085
|
52
|
2026-05-12T12:03:43.845930+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-12/1778 /Users/lukas/.screenpipe/data/data/2026-05-12/1778587423845_m2.jpg...
|
Claude
|
Claude
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Skip to content
Skip to content
Click to collapse
Skip to content
Skip to content
Click to collapse
⌘B
Drag to resize
Collapse sidebar
Search
Chat
Cowork
Code
New chat ⌘N
New chat
⌘N
Projects
Artifacts
Customize
Pinned
Bulgarian citizenship application process for EU residents
More options for Bulgarian citizenship application process for EU residents
Dawarich location tracking project
More options for Dawarich location tracking project
Recents
View all
Screenpipe data sync and retention management
More options for Screenpipe data sync and retention management
Screenpipe sync script failing after recent migrations
More options for Screenpipe sync script failing after recent migrations
Hubspot BadRequest headers debugging
More options for Hubspot BadRequest headers debugging
Monthly expense tracking
More options for Monthly expense tracking
Exporting transaction data from Notion to finance hub
More options for Exporting transaction data from Notion to finance hub
💬 How much have I spent for groc…
More options for 💬 How much have I spent for groc…
April 2026 spending by category
More options for April 2026 spending by category
Code diff review
More options for Code diff review
HubSpot rate limit implementation strategy
More options for HubSpot rate limit implementation strategy
Screenpipe retention policy code location
More options for Screenpipe retention policy code location
Viewing retention policy in screenpipe
More options for Viewing retention policy in screenpipe
Clean shot x video recording termination issue
More options for Clean shot x video recording termination issue
HubSpot rate limit handling with executeRequest
More options for HubSpot rate limit handling with executeRequest
Untitled
More options
💬 Screen pipe. Is there ability…
More options for 💬 Screen pipe. Is there ability…
SMB mount access inconsistency between Finder and iTerm
More options for SMB mount access inconsistency between Finder and iTerm
💬 What is the best switch I can…
More options for 💬 What is the best switch I can…
Permission denied on screenpipe volume
More options for Permission denied on screenpipe volume
Screenpipe sync database attachment error
More options for Screenpipe sync database attachment error
Last swimming outing with Dani
More options for Last swimming outing with Dani
Lukas Pro
Get apps and extensions
Screenpipe data sync and retention management, rename chat
Screenpipe data sync and retention management
More options for Screenpipe data sync and retention management
Open sidebar
Share chat
Claude finished the response
You said: Lets start from the beginning with the fresh mind.
You said: Lets start from the beginning with the fresh mind.
Pasted Text, pasted, 495 lines
#!/bin/bash # screenpipe_sync.sh # Syncs Screenpipe SQLite data to a NAS archive database (append-only, no deletions). # Also copies the day's video/frame data folder to the NAS. # # Schema-drift tolerant: if Screenpipe migrations add new columns to the source DB, # the NAS archive gets ALTER TABLE'
PASTED
Lets start from the beginning with the fresh mind. There is a script for screenpipe to copy data for day from mac to nas. There are two issues I want to work with. Firsts if I reinstall the mac version it starts from fresh id 1. That causes some issues. How to make sure the data are valid. I don't want some overcomplicated flow. I was thinking about making new db every 3 months. Secodn issue is that I wan to implement cleanup (retention policy) on mac original screenpipe db. I want script that will remove data that are 7 days old or older for example. ANd lastly I want to extedn the script to work with audio as well. What od you need
20:19
Retry
Edit
Copy
Claude responded: Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether…
Claude responded: Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether…
Analyzed three technical challenges and identified clarifying questions needed
Analyzed three technical challenges and identified clarifying questions needed
Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether reinstalls have already happened). Before I touch the script, a few things:
Issue 1 — ID collisions / archive rotation
Has a reinstall already happened, or is the current
archive.db
still from one continuous install? If collisions already exist I need to handle that first; if not, we have a clean slate.
Quarterly rotation works, but it doesn't actually solve reinstalls
within
a quarter. A cleaner option that I'd lean toward: add an
install_id
column (UUID generated once and stored in a tiny
_meta
table in the source DB) to every synced table, and make
(install_id, id)
the logical key. FK joins just gain one extra predicate. Reinstall → new install_id → no collisions, ever. You can still rotate the archive DB quarterly for file-size reasons, but it's no longer load-bearing.
Do you ever run cross-period queries (e.g. "every frame mentioning JY-20458 across all time")? That answers whether quarterly sharding is acceptable or whether one growing DB is better.
Issue 2 — Mac-side retention
Your launch command already has
--retention-days 7
. Is that not actually deleting anything, or do you want a separate scripted retention you can trust/observe independently?
Should retention also wipe the matching
~/.screenpipe/data/data/YYYY-MM-DD/
folders, or only DB rows? (CLI flag does both I believe; a script should match.)
Run order matters: sync writes
yesterday
, retention deletes
>7 days old
— no overlap, but I'd still chain them (sync → retention → log) in one cron entry so a failed sync blocks the delete. OK with that?
Issue 3 — Audio
Your current launch flag is
--disable-audio
, so right now there's no audio data to sync. Are you planning to enable it, or is this just to future-proof the script?
I need the audio schema. Could you run this and paste the output:
Copy to clipboard
sqlite3 ~/.screenpipe/db.sqlite ".schema" | grep -iE -A 20 "audio|transcription"
And:
ls ~/.screenpipe/data/data/$(date -v-1d +%Y-%m-%d)/ | head
so I can see what audio files look like on disk alongside the mp4 frames.
Once I have those, I'll restructure the script in one go rather than piecemeal.
Copy
Give positive feedback
Give negative feedback
Retry
You said: ok lets add install_id.
You said: ok lets add install_id.
Pasted Text, pasted, 208 lines
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ sqlite3 ~/.screenpipe/db.sqlite ".schema" | grep -iE -A 20 "audio|transcription" CREATE TABLE audio_chunks ( id INTEGER PRIMARY KEY AUTOINCREMENT, file_path TEXT NOT NULL , timestamp TIMESTAMP, sync_id TEXT, machine_id TEXT, synced_at DATETIME, ev
PASTED
ok lets add install_id. Lets add separate script deleting data again from data and it should also remove logs and data. Make it manual script for now. I will remove --disable-audio from alias and run it without. I wan to have audio as well. lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ ls ~/.screenpipe/data/data/$(date -v-1d +%Y-%m-%d)/ | head
compact_monitor_1_1778411210025.mp4
compact_monitor_1_1778413422547.mp4
compact_monitor_1_1778436664801.mp4
compact_monitor_1_1778437267451.mp4
compact_monitor_1_1778437569681.mp4
compact_monitor_1_1778437873507.mp4
compact_monitor_1_1778438175846.mp4
compact_monitor_1_1778438477299.mp4
compact_monitor_1_1778438780686.mp4
compact_monitor_1_1778439082442.mp4 Inside ~/,screenpipe/data there are data like this ... -rw-r--r-- 1 lukas staff 4628 11 May 16:48 System Audio (output)_2026-05-11_13-48-12.mp4
-rw-r--r-- 1 lukas staff 4620 11 May 16:48 System Audio (output)_2026-05-11_13-48-34.mp4
-rw-r--r-- 1 lukas staff 4620 11 May 16:49 System Audio (output)_2026-05-11_13-48-56.mp4
-rw-r--r-- 1 lukas staff 4628 11 May 16:49 System Audio (output)_2026-05-11_13-49-19.mp4
-rw-r--r-- 1 lukas staff 4620 11 May 16:50 System Audio (output)_2026-05-11_13-49-41.mp4
-rw-r--r-- 1 lukas staff 4620 11 May 16:50 System Audio (output)_2026-05-11_13-50-03.mp4
-rw-r--r-- 1 lukas staff 4628 11 May 16:50 System Audio (output)_2026-05-11_13-50-26.mp4
-rw-r--r-- 1 lukas staff 4628 11 May 16:51 System Audio (output)_2026-05-11_13-50-48.mp4
-rw-r--r-- 1 lukas staff 4620 11 May 16:51 System Audio (output)_2026-05-11_13-51-10.mp4
-rw-r--r-- 1 lukas staff 4620 11 May 16:51 System Audio (output)_2026-05-11_13-51-33.mp4
-rw-r--r-- 1 lukas staff 4620 11 May 16:52 System Audio (output)_2026-05-11_13-51-55.mp4
drwxr-xr-x 9 lukas staff 288 11 May 07:54 data
drwxr-xr-x 2 lukas staff 64 11 May 15:48 pending-transcriptions
-rw-r--r-- 1 lukas staff 29419 10 May 14:11 soundcore AeroClip (input)_2026-05-10_11-10-32.mp4
-rw-r--r-- 1 lukas staff 56479 10 May 14:11 soundcore AeroClip (input)_2026-05-10_11-11-05.mp4
-rw-r--r--@ 1 lukas staff 181831 10 May 14:12 soundcore AeroClip (input)_2026-05-10_11-11-35.mp4
-rw-r--r-- 1 lukas staff 149782 10 May 14:43 soundcore AeroClip (input)_2026-05-10_11-42-53.mp4
-rw-r--r-- 1 lukas staff 91059 10 May 14:43 soundcore AeroClip (input)_2026-05-10_11-43-25.mp4
-rw-r--r-- 1 lukas staff 30604 10 May 14:44 soundcore AeroClip (input)_2026-05-10_11-44-25.mp4
-rw-r--r-- 1 lukas staff 93813 10 May 14:45 soundcore AeroClip (input)_2026-05-10_11-44-55.mp4
-rw-r--r-- 1 lukas staff 40444 10 May 21:11 soundcore AeroClip (input)_2026-05-10_18-11-18.mp4
-rw-r--r-- 1 lukas staff 193020 10 May 21:12 soundcore AeroClip (input)_2026-05-10_18-11-48.mp4...
Show more
20:34
Retry
Edit
Copy
Claude responded: Good, that clarifies the audio layout — audio files live flat in ~/.
Claude responded: Good, that clarifies the audio layout — audio files live flat in ~/.
Architected multi-install sync with audio support and retention
Architected multi-install sync with audio support and retention
Good, that clarifies the audio layout — audio files live flat in
~/.screenpipe/data/
with the date in the filename (not in date subdirs like frames), and the schema gives us
audio_chunks
+
audio_transcriptions
+
speakers
+
speaker_embeddings
+
audio_tags
plus the FTS table on transcriptions.
Plan I'll implement:
install_id
: stored as a UUID in
~/.screenpipe/.sync_install_id
— disappears when the directory is wiped (which is what you want on reinstall). Every synced NAS table gets an
install_id TEXT
column and a
UNIQUE(install_id, id)
index. The script auto-migrates the existing NAS archive by adding the column and tagging legacy rows with
legacy-YYYYMMDD
so historical data is still queryable but doesn't conflict with future installs.
Audio sync
: adds
audio_chunks
,
audio_transcriptions
,
speakers
,
speaker_embeddings
,
audio_tags
to the sync pipeline, plus the
audio_transcriptions_fts
index. Audio files go to
$NAS_DATA/<date>/audio/
(sibling to the frames in the same date dir, keeps daily archives self-contained).
Retention
is a separate manual script — dry-run by default,
--apply
to delete. Hits DB rows, frame directories, audio mp4s, and screenpipe logs. Optional
--vacuum
with a warning (screenpipe must be stopped to avoid blocking writes for minutes).
One caveat I'm punting on: the FTS tables use source
id
as
rowid
, so after a reinstall they'd get id-collisions on insert and
INSERT OR IGNORE
would silently skip. Within a single install this is fine; after reinstall you'd fall back to
LIKE...
|
[{"role":"AXLink","text":& [{"role":"AXLink","text":"Skip to content","depth":14,"bounds":{"left":0.50232714,"top":0.025538707,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Skip to content","depth":15,"bounds":{"left":0.50232714,"top":0.026336791,"width":0.030917553,"height":0.013567438},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.50232714,"top":0.027134877,"width":0.0026595744,"height":0.012769354}},{"char_start":1,"char_count":14,"bounds":{"left":0.5049867,"top":0.027134877,"width":0.02825798,"height":0.012769354}}],"role_description":"text"},{"role":"AXStaticText","text":"Click to collapse","depth":16,"bounds":{"left":0.6023936,"top":0.3216281,"width":0.030917553,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.6023936,"top":0.3216281,"width":0.0029920214,"height":0.011971269}},{"char_start":1,"char_count":16,"bounds":{"left":0.60538566,"top":0.3216281,"width":0.027925532,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"⌘B","depth":16,"bounds":{"left":0.6349734,"top":0.3216281,"width":0.0066489363,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drag to resize","depth":16,"bounds":{"left":0.6023936,"top":0.33359936,"width":0.025930852,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.6023936,"top":0.33359936,"width":0.0029920214,"height":0.011971269}},{"char_start":1,"char_count":13,"bounds":{"left":0.60538566,"top":0.33359936,"width":0.022938829,"height":0.011971269}}],"role_description":"text"},{"role":"AXButton","text":"Collapse sidebar","depth":15,"bounds":{"left":0.5305851,"top":0.02952913,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search","depth":15,"bounds":{"left":0.53856385,"top":0.02952913,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Chat","depth":16,"bounds":{"left":0.50598407,"top":0.06304868,"width":0.026263298,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cowork","depth":16,"bounds":{"left":0.53291225,"top":0.06304868,"width":0.031914894,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code","depth":16,"bounds":{"left":0.56515956,"top":0.06304868,"width":0.027260639,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New chat ⌘N","depth":15,"bounds":{"left":0.5053192,"top":0.096568234,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"New chat","depth":16,"bounds":{"left":0.5152925,"top":0.09976058,"width":0.019614361,"height":0.013567438},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5152925,"top":0.10055866,"width":0.0033244682,"height":0.013567438}},{"char_start":1,"char_count":7,"bounds":{"left":0.51861703,"top":0.10055866,"width":0.015957447,"height":0.013567438}}],"role_description":"text"},{"role":"AXStaticText","text":"⌘N","depth":17,"bounds":{"left":0.5844415,"top":0.10055866,"width":0.0066489363,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Projects","depth":15,"bounds":{"left":0.5053192,"top":0.11731844,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Artifacts","depth":15,"bounds":{"left":0.5053192,"top":0.13806863,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Customize","depth":15,"bounds":{"left":0.5053192,"top":0.15881884,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Pinned","depth":16,"bounds":{"left":0.50731385,"top":0.19872306,"width":0.08510638,"height":0.012769354},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"Bulgarian citizenship application process for EU residents","depth":18,"bounds":{"left":0.5053192,"top":0.21548285,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Bulgarian citizenship application process for EU residents","depth":19,"bounds":{"left":0.58577126,"top":0.21867518,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Dawarich location tracking project","depth":18,"bounds":{"left":0.5053192,"top":0.23703113,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Dawarich location tracking project","depth":19,"bounds":{"left":0.58577126,"top":0.24022347,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Recents","depth":16,"bounds":{"left":0.50731385,"top":0.26735833,"width":0.06482713,"height":0.012769354},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"View all","depth":16,"bounds":{"left":0.5731383,"top":0.26735833,"width":0.019281914,"height":0.012769354},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Screenpipe data sync and retention management","depth":18,"bounds":{"left":0.5053192,"top":0.28411812,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Screenpipe data sync and retention management","depth":19,"bounds":{"left":0.58577126,"top":0.28731045,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Screenpipe sync script failing after recent migrations","depth":18,"bounds":{"left":0.5053192,"top":0.3056664,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Screenpipe sync script failing after recent migrations","depth":19,"bounds":{"left":0.58577126,"top":0.30885875,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hubspot BadRequest headers debugging","depth":18,"bounds":{"left":0.5053192,"top":0.3272147,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Hubspot BadRequest headers debugging","depth":19,"bounds":{"left":0.58577126,"top":0.33040702,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Monthly expense tracking","depth":18,"bounds":{"left":0.5053192,"top":0.34876296,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Monthly expense tracking","depth":19,"bounds":{"left":0.58577126,"top":0.3519553,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Exporting transaction data from Notion to finance hub","depth":18,"bounds":{"left":0.5053192,"top":0.37031126,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Exporting transaction data from Notion to finance hub","depth":19,"bounds":{"left":0.58577126,"top":0.3735036,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"💬 How much have I spent for groc…","depth":18,"bounds":{"left":0.5053192,"top":0.39185953,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for 💬 How much have I spent for groc…","depth":19,"bounds":{"left":0.58577126,"top":0.39505187,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"April 2026 spending by category","depth":18,"bounds":{"left":0.5053192,"top":0.41340783,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for April 2026 spending by category","depth":19,"bounds":{"left":0.58577126,"top":0.41660017,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code diff review","depth":18,"bounds":{"left":0.5053192,"top":0.4349561,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Code diff review","depth":19,"bounds":{"left":0.58577126,"top":0.43814844,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HubSpot rate limit implementation strategy","depth":18,"bounds":{"left":0.5053192,"top":0.45650437,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for HubSpot rate limit implementation strategy","depth":19,"bounds":{"left":0.58577126,"top":0.45969674,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Screenpipe retention policy code location","depth":18,"bounds":{"left":0.5053192,"top":0.47805268,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Screenpipe retention policy code location","depth":19,"bounds":{"left":0.58577126,"top":0.481245,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Viewing retention policy in screenpipe","depth":18,"bounds":{"left":0.5053192,"top":0.49960095,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Viewing retention policy in screenpipe","depth":19,"bounds":{"left":0.58577126,"top":0.5027933,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Clean shot x video recording termination issue","depth":18,"bounds":{"left":0.5053192,"top":0.5211492,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Clean shot x video recording termination issue","depth":19,"bounds":{"left":0.58577126,"top":0.5243416,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HubSpot rate limit handling with executeRequest","depth":18,"bounds":{"left":0.5053192,"top":0.54269755,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for HubSpot rate limit handling with executeRequest","depth":19,"bounds":{"left":0.58577126,"top":0.54588985,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Untitled","depth":18,"bounds":{"left":0.5053192,"top":0.5642458,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options","depth":19,"bounds":{"left":0.58577126,"top":0.5674381,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"💬 Screen pipe. Is there ability…","depth":18,"bounds":{"left":0.5053192,"top":0.5857941,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for 💬 Screen pipe. Is there ability…","depth":19,"bounds":{"left":0.58577126,"top":0.58898646,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"SMB mount access inconsistency between Finder and iTerm","depth":18,"bounds":{"left":0.5053192,"top":0.60734236,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for SMB mount access inconsistency between Finder and iTerm","depth":19,"bounds":{"left":0.58577126,"top":0.6105347,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"💬 What is the best switch I can…","depth":18,"bounds":{"left":0.5053192,"top":0.62889063,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for 💬 What is the best switch I can…","depth":19,"bounds":{"left":0.58577126,"top":0.632083,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Permission denied on screenpipe volume","depth":18,"bounds":{"left":0.5053192,"top":0.65043896,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Permission denied on screenpipe volume","depth":19,"bounds":{"left":0.58577126,"top":0.65363127,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Screenpipe sync database attachment error","depth":18,"bounds":{"left":0.5053192,"top":0.67198724,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Screenpipe sync database attachment error","depth":19,"bounds":{"left":0.58577126,"top":0.67517954,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Last swimming outing with Dani","depth":18,"bounds":{"left":0.5053192,"top":0.6935355,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Last swimming outing with Dani","depth":19,"bounds":{"left":0.58577126,"top":0.6967279,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Lukas Pro","depth":15,"bounds":{"left":0.5053192,"top":0.9696728,"width":0.03856383,"height":0.01915403},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Get apps and extensions","depth":15,"bounds":{"left":0.5851064,"top":0.9696728,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Screenpipe data sync and retention management, rename chat","depth":19,"bounds":{"left":0.6023936,"top":0.02793296,"width":0.11070479,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Screenpipe data sync and retention management","depth":21,"bounds":{"left":0.6037234,"top":0.031923383,"width":0.10804521,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.6037234,"top":0.031923383,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":44,"bounds":{"left":0.60671544,"top":0.031923383,"width":0.105053194,"height":0.014365523}}],"role_description":"text"},{"role":"AXPopUpButton","text":"More options for Screenpipe data sync and retention management","depth":19,"bounds":{"left":0.7134308,"top":0.02793296,"width":0.006981383,"height":0.022346368},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open sidebar","depth":21,"bounds":{"left":0.9734042,"top":0.026336791,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Share chat","depth":21,"bounds":{"left":0.98537236,"top":0.026336791,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Claude finished the response","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"You said: Lets start from the beginning with the fresh mind.","depth":20,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"You said: Lets start from the beginning with the fresh mind.","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Pasted Text, pasted, 495 lines","depth":21,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"#!/bin/bash # screenpipe_sync.sh # Syncs Screenpipe SQLite data to a NAS archive database (append-only, no deletions). # Also copies the day's video/frame data folder to the NAS. # # Schema-drift tolerant: if Screenpipe migrations add new columns to the source DB, # the NAS archive gets ALTER TABLE'","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PASTED","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Lets start from the beginning with the fresh mind. There is a script for screenpipe to copy data for day from mac to nas. There are two issues I want to work with. Firsts if I reinstall the mac version it starts from fresh id 1. That causes some issues. How to make sure the data are valid. I don't want some overcomplicated flow. I was thinking about making new db every 3 months. Secodn issue is that I wan to implement cleanup (retention policy) on mac original screenpipe db. I want script that will remove data that are 7 days old or older for example. ANd lastly I want to extedn the script to work with audio as well. What od you need","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"20:19","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Retry","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Edit","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Claude responded: Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether…","depth":21,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Claude responded: Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether…","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Analyzed three technical challenges and identified clarifying questions needed","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Analyzed three technical challenges and identified clarifying questions needed","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether reinstalls have already happened). Before I touch the script, a few things:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Issue 1 — ID collisions / archive rotation","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Has a reinstall already happened, or is the current","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"archive.db","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"still from one continuous install? If collisions already exist I need to handle that first; if not, we have a clean slate.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Quarterly rotation works, but it doesn't actually solve reinstalls","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"within","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"a quarter. A cleaner option that I'd lean toward: add an","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"install_id","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"column (UUID generated once and stored in a tiny","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"_meta","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"table in the source DB) to every synced table, and make","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(install_id, id)","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"the logical key. FK joins just gain one extra predicate. Reinstall → new install_id → no collisions, ever. You can still rotate the archive DB quarterly for file-size reasons, but it's no longer load-bearing.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Do you ever run cross-period queries (e.g. \"every frame mentioning JY-20458 across all time\")? That answers whether quarterly sharding is acceptable or whether one growing DB is better.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Issue 2 — Mac-side retention","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Your launch command already has","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"--retention-days 7","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":". Is that not actually deleting anything, or do you want a separate scripted retention you can trust/observe independently?","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Should retention also wipe the matching","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"~/.screenpipe/data/data/YYYY-MM-DD/","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"folders, or only DB rows? (CLI flag does both I believe; a script should match.)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Run order matters: sync writes","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"yesterday","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", retention deletes","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":">7 days old","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— no overlap, but I'd still chain them (sync → retention → log) in one cron entry so a failed sync blocks the delete. OK with that?","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Issue 3 — Audio","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Your current launch flag is","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"--disable-audio","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", so right now there's no audio data to sync. Are you planning to enable it, or is this just to future-proof the script?","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"I need the audio schema. Could you run this and paste the output:","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy to clipboard","depth":27,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"sqlite3 ~/.screenpipe/db.sqlite \".schema\" | grep -iE -A 20 \"audio|transcription\"","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"And:","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ls ~/.screenpipe/data/data/$(date -v-1d +%Y-%m-%d)/ | head","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"so I can see what audio files look like on disk alongside the mp4 frames.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Once I have those, I'll restructure the script in one go rather than piecemeal.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Give positive feedback","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Give negative feedback","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Retry","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"You said: ok lets add install_id.","depth":20,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"You said: ok lets add install_id.","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Pasted Text, pasted, 208 lines","depth":21,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ sqlite3 ~/.screenpipe/db.sqlite \".schema\" | grep -iE -A 20 \"audio|transcription\" CREATE TABLE audio_chunks ( id INTEGER PRIMARY KEY AUTOINCREMENT, file_path TEXT NOT NULL , timestamp TIMESTAMP, sync_id TEXT, machine_id TEXT, synced_at DATETIME, ev","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PASTED","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ok lets add install_id. Lets add separate script deleting data again from data and it should also remove logs and data. Make it manual script for now. I will remove --disable-audio from alias and run it without. I wan to have audio as well. lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ ls ~/.screenpipe/data/data/$(date -v-1d +%Y-%m-%d)/ | head\ncompact_monitor_1_1778411210025.mp4\ncompact_monitor_1_1778413422547.mp4\ncompact_monitor_1_1778436664801.mp4\ncompact_monitor_1_1778437267451.mp4\ncompact_monitor_1_1778437569681.mp4\ncompact_monitor_1_1778437873507.mp4\ncompact_monitor_1_1778438175846.mp4\ncompact_monitor_1_1778438477299.mp4\ncompact_monitor_1_1778438780686.mp4\ncompact_monitor_1_1778439082442.mp4 Inside ~/,screenpipe/data there are data like this ... -rw-r--r-- 1 lukas staff 4628 11 May 16:48 System Audio (output)_2026-05-11_13-48-12.mp4\n-rw-r--r-- 1 lukas staff 4620 11 May 16:48 System Audio (output)_2026-05-11_13-48-34.mp4\n-rw-r--r-- 1 lukas staff 4620 11 May 16:49 System Audio (output)_2026-05-11_13-48-56.mp4\n-rw-r--r-- 1 lukas staff 4628 11 May 16:49 System Audio (output)_2026-05-11_13-49-19.mp4\n-rw-r--r-- 1 lukas staff 4620 11 May 16:50 System Audio (output)_2026-05-11_13-49-41.mp4\n-rw-r--r-- 1 lukas staff 4620 11 May 16:50 System Audio (output)_2026-05-11_13-50-03.mp4\n-rw-r--r-- 1 lukas staff 4628 11 May 16:50 System Audio (output)_2026-05-11_13-50-26.mp4\n-rw-r--r-- 1 lukas staff 4628 11 May 16:51 System Audio (output)_2026-05-11_13-50-48.mp4\n-rw-r--r-- 1 lukas staff 4620 11 May 16:51 System Audio (output)_2026-05-11_13-51-10.mp4\n-rw-r--r-- 1 lukas staff 4620 11 May 16:51 System Audio (output)_2026-05-11_13-51-33.mp4\n-rw-r--r-- 1 lukas staff 4620 11 May 16:52 System Audio (output)_2026-05-11_13-51-55.mp4\ndrwxr-xr-x 9 lukas staff 288 11 May 07:54 data\ndrwxr-xr-x 2 lukas staff 64 11 May 15:48 pending-transcriptions\n-rw-r--r-- 1 lukas staff 29419 10 May 14:11 soundcore AeroClip (input)_2026-05-10_11-10-32.mp4\n-rw-r--r-- 1 lukas staff 56479 10 May 14:11 soundcore AeroClip (input)_2026-05-10_11-11-05.mp4\n-rw-r--r--@ 1 lukas staff 181831 10 May 14:12 soundcore AeroClip (input)_2026-05-10_11-11-35.mp4\n-rw-r--r-- 1 lukas staff 149782 10 May 14:43 soundcore AeroClip (input)_2026-05-10_11-42-53.mp4\n-rw-r--r-- 1 lukas staff 91059 10 May 14:43 soundcore AeroClip (input)_2026-05-10_11-43-25.mp4\n-rw-r--r-- 1 lukas staff 30604 10 May 14:44 soundcore AeroClip (input)_2026-05-10_11-44-25.mp4\n-rw-r--r-- 1 lukas staff 93813 10 May 14:45 soundcore AeroClip (input)_2026-05-10_11-44-55.mp4\n-rw-r--r-- 1 lukas staff 40444 10 May 21:11 soundcore AeroClip (input)_2026-05-10_18-11-18.mp4\n-rw-r--r-- 1 lukas staff 193020 10 May 21:12 soundcore AeroClip (input)_2026-05-10_18-11-48.mp4...","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Show more","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"20:34","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Retry","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Edit","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Claude responded: Good, that clarifies the audio layout — audio files live flat in ~/.","depth":21,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Claude responded: Good, that clarifies the audio layout — audio files live flat in ~/.","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Architected multi-install sync with audio support and retention","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Architected multi-install sync with audio support and retention","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Good, that clarifies the audio layout — audio files live flat in","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"~/.screenpipe/data/","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"with the date in the filename (not in date subdirs like frames), and the schema gives us","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"audio_chunks","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"+","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"audio_transcriptions","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"+","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"speakers","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"+","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"speaker_embeddings","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"+","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"audio_tags","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"plus the FTS table on transcriptions.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Plan I'll implement:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"install_id","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":": stored as a UUID in","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"~/.screenpipe/.sync_install_id","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— disappears when the directory is wiped (which is what you want on reinstall). Every synced NAS table gets an","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"install_id TEXT","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"column and a","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"UNIQUE(install_id, id)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"index. The script auto-migrates the existing NAS archive by adding the column and tagging legacy rows with","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"legacy-YYYYMMDD","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"so historical data is still queryable but doesn't conflict with future installs.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Audio sync","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":": adds","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"audio_chunks","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"audio_transcriptions","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"speakers","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"speaker_embeddings","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"audio_tags","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"to the sync pipeline, plus the","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"audio_transcriptions_fts","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"index. Audio files go to","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"$NAS_DATA/<date>/audio/","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(sibling to the frames in the same date dir, keeps daily archives self-contained).","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Retention","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"is a separate manual script — dry-run by default,","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"--apply","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"to delete. Hits DB rows, frame directories, audio mp4s, and screenpipe logs. Optional","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"--vacuum","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"with a warning (screenpipe must be stopped to avoid blocking writes for minutes).","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"One caveat I'm punting on: the FTS tables use source","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"id","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"as","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"rowid","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", so after a reinstall they'd get id-collisions on insert and","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"INSERT OR IGNORE","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"would silently skip. Within a single install this is fine; after reinstall you'd fall back to","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LIKE","depth":26,"on_screen":false,"role_description":"text"}]...
|
-8093342560456889723
|
-8498644826101647289
|
visual_change
|
accessibility
|
NULL
|
Skip to content
Skip to content
Click to collapse
Skip to content
Skip to content
Click to collapse
⌘B
Drag to resize
Collapse sidebar
Search
Chat
Cowork
Code
New chat ⌘N
New chat
⌘N
Projects
Artifacts
Customize
Pinned
Bulgarian citizenship application process for EU residents
More options for Bulgarian citizenship application process for EU residents
Dawarich location tracking project
More options for Dawarich location tracking project
Recents
View all
Screenpipe data sync and retention management
More options for Screenpipe data sync and retention management
Screenpipe sync script failing after recent migrations
More options for Screenpipe sync script failing after recent migrations
Hubspot BadRequest headers debugging
More options for Hubspot BadRequest headers debugging
Monthly expense tracking
More options for Monthly expense tracking
Exporting transaction data from Notion to finance hub
More options for Exporting transaction data from Notion to finance hub
💬 How much have I spent for groc…
More options for 💬 How much have I spent for groc…
April 2026 spending by category
More options for April 2026 spending by category
Code diff review
More options for Code diff review
HubSpot rate limit implementation strategy
More options for HubSpot rate limit implementation strategy
Screenpipe retention policy code location
More options for Screenpipe retention policy code location
Viewing retention policy in screenpipe
More options for Viewing retention policy in screenpipe
Clean shot x video recording termination issue
More options for Clean shot x video recording termination issue
HubSpot rate limit handling with executeRequest
More options for HubSpot rate limit handling with executeRequest
Untitled
More options
💬 Screen pipe. Is there ability…
More options for 💬 Screen pipe. Is there ability…
SMB mount access inconsistency between Finder and iTerm
More options for SMB mount access inconsistency between Finder and iTerm
💬 What is the best switch I can…
More options for 💬 What is the best switch I can…
Permission denied on screenpipe volume
More options for Permission denied on screenpipe volume
Screenpipe sync database attachment error
More options for Screenpipe sync database attachment error
Last swimming outing with Dani
More options for Last swimming outing with Dani
Lukas Pro
Get apps and extensions
Screenpipe data sync and retention management, rename chat
Screenpipe data sync and retention management
More options for Screenpipe data sync and retention management
Open sidebar
Share chat
Claude finished the response
You said: Lets start from the beginning with the fresh mind.
You said: Lets start from the beginning with the fresh mind.
Pasted Text, pasted, 495 lines
#!/bin/bash # screenpipe_sync.sh # Syncs Screenpipe SQLite data to a NAS archive database (append-only, no deletions). # Also copies the day's video/frame data folder to the NAS. # # Schema-drift tolerant: if Screenpipe migrations add new columns to the source DB, # the NAS archive gets ALTER TABLE'
PASTED
Lets start from the beginning with the fresh mind. There is a script for screenpipe to copy data for day from mac to nas. There are two issues I want to work with. Firsts if I reinstall the mac version it starts from fresh id 1. That causes some issues. How to make sure the data are valid. I don't want some overcomplicated flow. I was thinking about making new db every 3 months. Secodn issue is that I wan to implement cleanup (retention policy) on mac original screenpipe db. I want script that will remove data that are 7 days old or older for example. ANd lastly I want to extedn the script to work with audio as well. What od you need
20:19
Retry
Edit
Copy
Claude responded: Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether…
Claude responded: Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether…
Analyzed three technical challenges and identified clarifying questions needed
Analyzed three technical challenges and identified clarifying questions needed
Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether reinstalls have already happened). Before I touch the script, a few things:
Issue 1 — ID collisions / archive rotation
Has a reinstall already happened, or is the current
archive.db
still from one continuous install? If collisions already exist I need to handle that first; if not, we have a clean slate.
Quarterly rotation works, but it doesn't actually solve reinstalls
within
a quarter. A cleaner option that I'd lean toward: add an
install_id
column (UUID generated once and stored in a tiny
_meta
table in the source DB) to every synced table, and make
(install_id, id)
the logical key. FK joins just gain one extra predicate. Reinstall → new install_id → no collisions, ever. You can still rotate the archive DB quarterly for file-size reasons, but it's no longer load-bearing.
Do you ever run cross-period queries (e.g. "every frame mentioning JY-20458 across all time")? That answers whether quarterly sharding is acceptable or whether one growing DB is better.
Issue 2 — Mac-side retention
Your launch command already has
--retention-days 7
. Is that not actually deleting anything, or do you want a separate scripted retention you can trust/observe independently?
Should retention also wipe the matching
~/.screenpipe/data/data/YYYY-MM-DD/
folders, or only DB rows? (CLI flag does both I believe; a script should match.)
Run order matters: sync writes
yesterday
, retention deletes
>7 days old
— no overlap, but I'd still chain them (sync → retention → log) in one cron entry so a failed sync blocks the delete. OK with that?
Issue 3 — Audio
Your current launch flag is
--disable-audio
, so right now there's no audio data to sync. Are you planning to enable it, or is this just to future-proof the script?
I need the audio schema. Could you run this and paste the output:
Copy to clipboard
sqlite3 ~/.screenpipe/db.sqlite ".schema" | grep -iE -A 20 "audio|transcription"
And:
ls ~/.screenpipe/data/data/$(date -v-1d +%Y-%m-%d)/ | head
so I can see what audio files look like on disk alongside the mp4 frames.
Once I have those, I'll restructure the script in one go rather than piecemeal.
Copy
Give positive feedback
Give negative feedback
Retry
You said: ok lets add install_id.
You said: ok lets add install_id.
Pasted Text, pasted, 208 lines
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ sqlite3 ~/.screenpipe/db.sqlite ".schema" | grep -iE -A 20 "audio|transcription" CREATE TABLE audio_chunks ( id INTEGER PRIMARY KEY AUTOINCREMENT, file_path TEXT NOT NULL , timestamp TIMESTAMP, sync_id TEXT, machine_id TEXT, synced_at DATETIME, ev
PASTED
ok lets add install_id. Lets add separate script deleting data again from data and it should also remove logs and data. Make it manual script for now. I will remove --disable-audio from alias and run it without. I wan to have audio as well. lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ ls ~/.screenpipe/data/data/$(date -v-1d +%Y-%m-%d)/ | head
compact_monitor_1_1778411210025.mp4
compact_monitor_1_1778413422547.mp4
compact_monitor_1_1778436664801.mp4
compact_monitor_1_1778437267451.mp4
compact_monitor_1_1778437569681.mp4
compact_monitor_1_1778437873507.mp4
compact_monitor_1_1778438175846.mp4
compact_monitor_1_1778438477299.mp4
compact_monitor_1_1778438780686.mp4
compact_monitor_1_1778439082442.mp4 Inside ~/,screenpipe/data there are data like this ... -rw-r--r-- 1 lukas staff 4628 11 May 16:48 System Audio (output)_2026-05-11_13-48-12.mp4
-rw-r--r-- 1 lukas staff 4620 11 May 16:48 System Audio (output)_2026-05-11_13-48-34.mp4
-rw-r--r-- 1 lukas staff 4620 11 May 16:49 System Audio (output)_2026-05-11_13-48-56.mp4
-rw-r--r-- 1 lukas staff 4628 11 May 16:49 System Audio (output)_2026-05-11_13-49-19.mp4
-rw-r--r-- 1 lukas staff 4620 11 May 16:50 System Audio (output)_2026-05-11_13-49-41.mp4
-rw-r--r-- 1 lukas staff 4620 11 May 16:50 System Audio (output)_2026-05-11_13-50-03.mp4
-rw-r--r-- 1 lukas staff 4628 11 May 16:50 System Audio (output)_2026-05-11_13-50-26.mp4
-rw-r--r-- 1 lukas staff 4628 11 May 16:51 System Audio (output)_2026-05-11_13-50-48.mp4
-rw-r--r-- 1 lukas staff 4620 11 May 16:51 System Audio (output)_2026-05-11_13-51-10.mp4
-rw-r--r-- 1 lukas staff 4620 11 May 16:51 System Audio (output)_2026-05-11_13-51-33.mp4
-rw-r--r-- 1 lukas staff 4620 11 May 16:52 System Audio (output)_2026-05-11_13-51-55.mp4
drwxr-xr-x 9 lukas staff 288 11 May 07:54 data
drwxr-xr-x 2 lukas staff 64 11 May 15:48 pending-transcriptions
-rw-r--r-- 1 lukas staff 29419 10 May 14:11 soundcore AeroClip (input)_2026-05-10_11-10-32.mp4
-rw-r--r-- 1 lukas staff 56479 10 May 14:11 soundcore AeroClip (input)_2026-05-10_11-11-05.mp4
-rw-r--r--@ 1 lukas staff 181831 10 May 14:12 soundcore AeroClip (input)_2026-05-10_11-11-35.mp4
-rw-r--r-- 1 lukas staff 149782 10 May 14:43 soundcore AeroClip (input)_2026-05-10_11-42-53.mp4
-rw-r--r-- 1 lukas staff 91059 10 May 14:43 soundcore AeroClip (input)_2026-05-10_11-43-25.mp4
-rw-r--r-- 1 lukas staff 30604 10 May 14:44 soundcore AeroClip (input)_2026-05-10_11-44-25.mp4
-rw-r--r-- 1 lukas staff 93813 10 May 14:45 soundcore AeroClip (input)_2026-05-10_11-44-55.mp4
-rw-r--r-- 1 lukas staff 40444 10 May 21:11 soundcore AeroClip (input)_2026-05-10_18-11-18.mp4
-rw-r--r-- 1 lukas staff 193020 10 May 21:12 soundcore AeroClip (input)_2026-05-10_18-11-48.mp4...
Show more
20:34
Retry
Edit
Copy
Claude responded: Good, that clarifies the audio layout — audio files live flat in ~/.
Claude responded: Good, that clarifies the audio layout — audio files live flat in ~/.
Architected multi-install sync with audio support and retention
Architected multi-install sync with audio support and retention
Good, that clarifies the audio layout — audio files live flat in
~/.screenpipe/data/
with the date in the filename (not in date subdirs like frames), and the schema gives us
audio_chunks
+
audio_transcriptions
+
speakers
+
speaker_embeddings
+
audio_tags
plus the FTS table on transcriptions.
Plan I'll implement:
install_id
: stored as a UUID in
~/.screenpipe/.sync_install_id
— disappears when the directory is wiped (which is what you want on reinstall). Every synced NAS table gets an
install_id TEXT
column and a
UNIQUE(install_id, id)
index. The script auto-migrates the existing NAS archive by adding the column and tagging legacy rows with
legacy-YYYYMMDD
so historical data is still queryable but doesn't conflict with future installs.
Audio sync
: adds
audio_chunks
,
audio_transcriptions
,
speakers
,
speaker_embeddings
,
audio_tags
to the sync pipeline, plus the
audio_transcriptions_fts
index. Audio files go to
$NAS_DATA/<date>/audio/
(sibling to the frames in the same date dir, keeps daily archives self-contained).
Retention
is a separate manual script — dry-run by default,
--apply
to delete. Hits DB rows, frame directories, audio mp4s, and screenpipe logs. Optional
--vacuum
with a warning (screenpipe must be stopped to avoid blocking writes for minutes).
One caveat I'm punting on: the FTS tables use source
id
as
rowid
, so after a reinstall they'd get id-collisions on insert and
INSERT OR IGNORE
would silently skip. Within a single install this is fine; after reinstall you'd fall back to
LIKE...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
3496
|
129
|
15
|
2026-05-07T12:22:59.959095+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778156579959_m1.jpg...
|
iTerm2
|
NULL
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
iTerm2ShellEditViewSessionScriptsProfilesWindowHel iTerm2ShellEditViewSessionScriptsProfilesWindowHelp# Lukas/Stefka 121 • in 2h 8 mA100% <478DEV (docker)DOCKERO &1DEV (docker)882APP (-zsh)Jiminny-worker-processing-4:jiminny-worker-processing-4_00:jiminny-worker-processing-5:jiminny-worker-processing-5_00:stoppedstoppedworker-crm-update:worker-crm-update_00: stoppedworker-analytics:worker-analytics_00: stoppedworker-download:worker-download_00: stoppedworker:worker_00: stoppedjiminny-worker-processing-1:jiminny-worker-processing-1_00: stoppedworker-calendar:worker-calendar_00:stoppedworker-conferences:worker-conferences_00: stoppedworker-crm-sync:worker-crm-sync_00:stoppedworker-audio:worker-audio_00: stoppedworker-emails:worker-emails_00:stoppedartisan-schedule:artisan-schedule_00: stoppedworker-es-update:worker-es-update_00: stoppedartisan-schedule:artisan-schedule_00: startedjiminny-worker-processing-1:jiminny-worker-processing-1_00: startedjiminny-worker-processing-2:jiminny-worker-processing-2_00: startedjiminny-worker-processing-3:jiminny-worker-processing-3_00: startedjiminny-worker-processing-4:jiminny-worker-processing-4_00: startedjiminny-worker-processing-5:jiminny-worker-processing-5_00: startedjiminny-worker-processing-delayed: jiminny-worker-processing-delayed_00: startedworker:worker_00: startedworker-analytics:worker-analytics_00: startedworker-audio:worker-audio_00: startedworker-calendar:worker-calendar_00: startedworker-conferences:worker-conferences_00: startedworker-crm-sync:worker-crm-sync_00: startedworker-crm-update:worker-crm-update_00: startedworker-download:worker-download_00:startedworker-emails:worker-emails_00: startedworker-es-update:worker-es-update_00: startedworker-nudges:worker-nudges_00: startedroot@docker_lamp_1:/home/jiminny# php artisan jiminny:debugSyncing opportunity 0Syncing opportunity 25Syncing opportunity 50Syncing opportunity 75Syncing opportunity 100root@docker_lamp_1:/home/jiminny# php artisan jiminny: debugSyncing opportunity 0Syncing opportunity 25Syncing opportunity 50Syncing opportunity 75Syncing opportunity 100root@docker_lamp_1:/home/jiminny# ]-zsh• $4screenpipe*•$5-zshThu 7 May 15:22:59T81₴6DEV...
|
NULL
|
-8091834132265158449
|
NULL
|
click
|
ocr
|
NULL
|
iTerm2ShellEditViewSessionScriptsProfilesWindowHel iTerm2ShellEditViewSessionScriptsProfilesWindowHelp# Lukas/Stefka 121 • in 2h 8 mA100% <478DEV (docker)DOCKERO &1DEV (docker)882APP (-zsh)Jiminny-worker-processing-4:jiminny-worker-processing-4_00:jiminny-worker-processing-5:jiminny-worker-processing-5_00:stoppedstoppedworker-crm-update:worker-crm-update_00: stoppedworker-analytics:worker-analytics_00: stoppedworker-download:worker-download_00: stoppedworker:worker_00: stoppedjiminny-worker-processing-1:jiminny-worker-processing-1_00: stoppedworker-calendar:worker-calendar_00:stoppedworker-conferences:worker-conferences_00: stoppedworker-crm-sync:worker-crm-sync_00:stoppedworker-audio:worker-audio_00: stoppedworker-emails:worker-emails_00:stoppedartisan-schedule:artisan-schedule_00: stoppedworker-es-update:worker-es-update_00: stoppedartisan-schedule:artisan-schedule_00: startedjiminny-worker-processing-1:jiminny-worker-processing-1_00: startedjiminny-worker-processing-2:jiminny-worker-processing-2_00: startedjiminny-worker-processing-3:jiminny-worker-processing-3_00: startedjiminny-worker-processing-4:jiminny-worker-processing-4_00: startedjiminny-worker-processing-5:jiminny-worker-processing-5_00: startedjiminny-worker-processing-delayed: jiminny-worker-processing-delayed_00: startedworker:worker_00: startedworker-analytics:worker-analytics_00: startedworker-audio:worker-audio_00: startedworker-calendar:worker-calendar_00: startedworker-conferences:worker-conferences_00: startedworker-crm-sync:worker-crm-sync_00: startedworker-crm-update:worker-crm-update_00: startedworker-download:worker-download_00:startedworker-emails:worker-emails_00: startedworker-es-update:worker-es-update_00: startedworker-nudges:worker-nudges_00: startedroot@docker_lamp_1:/home/jiminny# php artisan jiminny:debugSyncing opportunity 0Syncing opportunity 25Syncing opportunity 50Syncing opportunity 75Syncing opportunity 100root@docker_lamp_1:/home/jiminny# php artisan jiminny: debugSyncing opportunity 0Syncing opportunity 25Syncing opportunity 50Syncing opportunity 75Syncing opportunity 100root@docker_lamp_1:/home/jiminny# ]-zsh• $4screenpipe*•$5-zshThu 7 May 15:22:59T81₴6DEV...
|
3494
|
NULL
|
NULL
|
NULL
|
|
15608
|
695
|
2
|
2026-05-11T07:04:24.318989+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778483064318_m2.jpg...
|
Firefox
|
Google Meet — Work
|
True
|
meet.google.com/landing?authuser=lukas.kovalik@jim meet.google.com/landing?authuser=lukas.kovalik@jiminny.com...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Google Meet
Close tab
New Tab
Open Google Gemini ( Google Meet
Close tab
New Tab
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Customize sidebar
Main menu
Google Meet
Meet
10:04 AM
•
Mon, May 11
Support
Report a problem
Settings
Google apps
Google Account: [EMAIL]
Meetings
Meetings
Calls
Calls
Secure video conferencing for everyone
Secure video conferencing for everyone
Connect, collaborate, and celebrate from anywhere with
Google Meet
New meeting
New meeting
Enter a code or nickname
Join
Join
9:45 AM to 10:05 AM. Daily - Platform. This meeting has started.
9:45 AM
Daily - Platform
Now
3:00 PM to 3:15 PM. Support Daily.
3:00 PM
Support Daily
3:00 PM to 4:00 PM. Preparation for Refinement.
3:00 PM
Preparation for Refinement
4:00 PM to 5:00 PM. [Platform] Refinement 🔍.
4:00 PM
[Platform] Refinement 🔍
From your Google Calendar account: [EMAIL]
Learn more about Google Meet
Learn more
about Google Meet...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Google Meet","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.016123671,"height":-0.051875472},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.27094415,"top":1.0,"width":0.004986702,"height":-0.051875472},"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.27310506,"top":1.0,"width":0.010638298,"height":-0.086193085},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"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,"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,"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,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Main menu","depth":9,"bounds":{"left":0.29039228,"top":1.0,"width":0.015957447,"height":-0.058260202},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXLink","text":"Google Meet","depth":10,"bounds":{"left":0.30767953,"top":1.0,"width":0.05900931,"height":-0.059856296},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Meet","depth":12,"bounds":{"left":0.35023272,"top":1.0,"width":0.016456118,"height":-0.06703913},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"10:04 AM","depth":10,"bounds":{"left":0.60754657,"top":1.0,"width":0.025265958,"height":-0.06823623},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":10,"bounds":{"left":0.6328125,"top":1.0,"width":0.004986702,"height":-0.06823623},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mon, May 11","depth":10,"bounds":{"left":0.6377992,"top":1.0,"width":0.03274601,"height":-0.06823623},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Support","depth":11,"bounds":{"left":0.67453456,"top":1.0,"width":0.013297873,"height":-0.061452508},"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":"Report a problem","depth":11,"bounds":{"left":0.6878325,"top":1.0,"width":0.013297873,"height":-0.061452508},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Settings","depth":11,"bounds":{"left":0.70113033,"top":1.0,"width":0.013297873,"height":-0.061452508},"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":11,"bounds":{"left":0.7150931,"top":1.0,"width":0.013297873,"height":-0.061452508},"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":"Google Account: lukas.kovalik@jiminny.com","depth":11,"bounds":{"left":0.73105055,"top":1.0,"width":0.013297873,"height":-0.061452508},"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":"Meetings","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Meetings","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Calls","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Calls","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Secure video conferencing for everyone","depth":10,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Secure video conferencing for everyone","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Connect, collaborate, and celebrate from anywhere with","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Google Meet","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New meeting","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":"AXStaticText","text":"New meeting","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Enter a code or nickname","depth":10,"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Join","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Join","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"9:45 AM to 10:05 AM. Daily - Platform. This meeting has started.","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false},{"role":"AXStaticText","text":"9:45 AM","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Daily - Platform","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Now","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"3:00 PM to 3:15 PM. Support Daily.","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3:00 PM","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Support Daily","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"3:00 PM to 4:00 PM. Preparation for Refinement.","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3:00 PM","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Preparation for Refinement","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"4:00 PM to 5:00 PM. [Platform] Refinement 🔍.","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4:00 PM","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[Platform] Refinement 🔍","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"From your Google Calendar account: lukas.kovalik@jiminny.com","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Learn more about Google Meet","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Learn more","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"about Google Meet","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-8086202985572363075
|
1734439298472096902
|
click
|
accessibility
|
NULL
|
Google Meet
Close tab
New Tab
Open Google Gemini ( Google Meet
Close tab
New Tab
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Customize sidebar
Main menu
Google Meet
Meet
10:04 AM
•
Mon, May 11
Support
Report a problem
Settings
Google apps
Google Account: [EMAIL]
Meetings
Meetings
Calls
Calls
Secure video conferencing for everyone
Secure video conferencing for everyone
Connect, collaborate, and celebrate from anywhere with
Google Meet
New meeting
New meeting
Enter a code or nickname
Join
Join
9:45 AM to 10:05 AM. Daily - Platform. This meeting has started.
9:45 AM
Daily - Platform
Now
3:00 PM to 3:15 PM. Support Daily.
3:00 PM
Support Daily
3:00 PM to 4:00 PM. Preparation for Refinement.
3:00 PM
Preparation for Refinement
4:00 PM to 5:00 PM. [Platform] Refinement 🔍.
4:00 PM
[Platform] Refinement 🔍
From your Google Calendar account: [EMAIL]
Learn more about Google Meet
Learn more
about Google Meet...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
15609
|
694
|
4
|
2026-05-11T07:04:25.918266+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778483065918_m1.jpg...
|
Firefox
|
Google Meet — Work
|
True
|
meet.google.com/landing?authuser=lukas.kovalik@jim meet.google.com/landing?authuser=lukas.kovalik@jiminny.com...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Google Meet
Close tab
New Tab
Open Google Gemini ( Google Meet
Close tab
New Tab
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Customize sidebar
Main menu
Google Meet
Meet
10:04 AM
•
Mon, May 11
Support
Report a problem
Settings
Google apps
Google Account: [EMAIL]
Meetings
Meetings
Calls
Calls
Secure video conferencing for everyone
Secure video conferencing for everyone
Connect, collaborate, and celebrate from anywhere with
Google Meet
New meeting
New meeting
Enter a code or nickname
Join
Join
9:45 AM to 10:05 AM. Daily - Platform. This meeting has started.
9:45 AM
Daily - Platform
Now
3:00 PM to 3:15 PM. Support Daily.
3:00 PM
Support Daily
3:00 PM to 4:00 PM. Preparation for Refinement.
3:00 PM
Preparation for Refinement
4:00 PM to 5:00 PM. [Platform] Refinement 🔍.
4:00 PM
[Platform] Refinement 🔍
From your Google Calendar account: [EMAIL]
Learn more about Google Meet
Learn more
about Google Meet...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Google Meet","depth":4,"bounds":{"left":0.0,"top":0.072222225,"width":0.033680554,"height":0.045555554},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0013888889,"top":0.072222225,"width":0.010416667,"height":0.016666668},"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.005902778,"top":0.12,"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},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.0,"top":0.7977778,"width":0.033680554,"height":0.043333333},"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.8411111,"width":0.033680554,"height":0.038333334},"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.8794444,"width":0.033680554,"height":0.03888889},"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.0,"top":0.91833335,"width":0.033680554,"height":0.038333334},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0,"top":0.95666665,"width":0.033680554,"height":0.043333333},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Main menu","depth":9,"bounds":{"left":0.042013887,"top":0.08111111,"width":0.033333335,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXLink","text":"Google Meet","depth":10,"bounds":{"left":0.078125,"top":0.083333336,"width":0.12326389,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Meet","depth":12,"bounds":{"left":0.16701388,"top":0.093333334,"width":0.034375,"height":0.030555556},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"10:04 AM","depth":10,"bounds":{"left":0.7045139,"top":0.095,"width":0.05277778,"height":0.025555555},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":10,"bounds":{"left":0.7572917,"top":0.095,"width":0.010416667,"height":0.025555555},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mon, May 11","depth":10,"bounds":{"left":0.76770836,"top":0.095,"width":0.068402775,"height":0.025555555},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Support","depth":11,"bounds":{"left":0.84444445,"top":0.08555555,"width":0.027777778,"height":0.044444446},"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":"Report a problem","depth":11,"bounds":{"left":0.87222224,"top":0.08555555,"width":0.027777778,"height":0.044444446},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Settings","depth":11,"bounds":{"left":0.9,"top":0.08555555,"width":0.027777778,"height":0.044444446},"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":11,"bounds":{"left":0.9291667,"top":0.08555555,"width":0.027777778,"height":0.044444446},"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":"Google Account: lukas.kovalik@jiminny.com","depth":11,"bounds":{"left":0.9625,"top":0.08555555,"width":0.027777778,"height":0.044444446},"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":"Meetings","depth":11,"bounds":{"left":0.033680554,"top":0.17,"width":0.17777778,"height":0.062222224},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Meetings","depth":14,"bounds":{"left":0.072569445,"top":0.19,"width":0.04826389,"height":0.022777777},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Calls","depth":11,"bounds":{"left":0.033680554,"top":0.23222223,"width":0.17777778,"height":0.062222224},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Calls","depth":14,"bounds":{"left":0.072569445,"top":0.2522222,"width":0.025,"height":0.022777777},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Secure video conferencing for everyone","depth":10,"bounds":{"left":0.40034723,"top":0.18055555,"width":0.41111112,"height":0.12444445},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Secure video conferencing for everyone","depth":11,"bounds":{"left":0.41805556,"top":0.17833333,"width":0.37534723,"height":0.12055556},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Connect, collaborate, and celebrate from anywhere with","depth":11,"bounds":{"left":0.41284722,"top":0.305,"width":0.38576388,"height":0.031111112},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Google Meet","depth":11,"bounds":{"left":0.56041664,"top":0.3361111,"width":0.090625,"height":0.031111112},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New meeting","depth":11,"bounds":{"left":0.40034723,"top":0.4027778,"width":0.10138889,"height":0.053333335},"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":"New meeting","depth":13,"bounds":{"left":0.43090278,"top":0.41944444,"width":0.059722222,"height":0.020555556},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Enter a code or nickname","depth":10,"bounds":{"left":0.54895836,"top":0.4027778,"width":0.15486111,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Join","depth":11,"bounds":{"left":0.7204861,"top":0.4027778,"width":0.044444446,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Join","depth":13,"bounds":{"left":0.7329861,"top":0.41944444,"width":0.019097222,"height":0.020555556},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"9:45 AM to 10:05 AM. Daily - Platform. This meeting has started.","depth":11,"bounds":{"left":0.38993055,"top":0.54555553,"width":0.43159723,"height":0.07444444},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false},{"role":"AXStaticText","text":"9:45 AM","depth":13,"bounds":{"left":0.40763888,"top":0.57166666,"width":0.042708334,"height":0.022222223},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Daily - Platform","depth":13,"bounds":{"left":0.48541668,"top":0.5694444,"width":0.09340278,"height":0.026666667},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Now","depth":12,"bounds":{"left":0.7864583,"top":0.575,"width":0.016666668,"height":0.015555556},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"3:00 PM to 3:15 PM. Support Daily.","depth":11,"bounds":{"left":0.40034723,"top":0.63,"width":0.41111112,"height":0.07111111},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3:00 PM","depth":13,"bounds":{"left":0.41701388,"top":0.655,"width":0.039930556,"height":0.02111111},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Support Daily","depth":13,"bounds":{"left":0.49131945,"top":0.6527778,"width":0.07534722,"height":0.025555555},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"3:00 PM to 4:00 PM. Preparation for Refinement.","depth":11,"bounds":{"left":0.40034723,"top":0.7127778,"width":0.41111112,"height":0.07111111},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3:00 PM","depth":13,"bounds":{"left":0.41701388,"top":0.73777777,"width":0.039930556,"height":0.02111111},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Preparation for Refinement","depth":13,"bounds":{"left":0.49131945,"top":0.7355555,"width":0.15208334,"height":0.025555555},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"4:00 PM to 5:00 PM. [Platform] Refinement 🔍.","depth":11,"bounds":{"left":0.40034723,"top":0.79555553,"width":0.41111112,"height":0.072222225},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4:00 PM","depth":13,"bounds":{"left":0.41701388,"top":0.8211111,"width":0.039930556,"height":0.02111111},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[Platform] Refinement 🔍","depth":13,"bounds":{"left":0.49131945,"top":0.8183333,"width":0.13819444,"height":0.026666667},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"From your Google Calendar account: lukas.kovalik@jiminny.com","depth":11,"bounds":{"left":0.40034723,"top":0.9088889,"width":0.23680556,"height":0.016111111},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Learn more about Google Meet","depth":11,"bounds":{"left":0.40034723,"top":0.945,"width":0.043402776,"height":0.017222222},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Learn more","depth":12,"bounds":{"left":0.40034723,"top":0.945,"width":0.043402776,"height":0.017222222},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"about Google Meet","depth":11,"bounds":{"left":0.44375,"top":0.945,"width":0.07638889,"height":0.017222222},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-8086202985572363075
|
1734439298472096902
|
visual_change
|
accessibility
|
NULL
|
Google Meet
Close tab
New Tab
Open Google Gemini ( Google Meet
Close tab
New Tab
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Customize sidebar
Main menu
Google Meet
Meet
10:04 AM
•
Mon, May 11
Support
Report a problem
Settings
Google apps
Google Account: [EMAIL]
Meetings
Meetings
Calls
Calls
Secure video conferencing for everyone
Secure video conferencing for everyone
Connect, collaborate, and celebrate from anywhere with
Google Meet
New meeting
New meeting
Enter a code or nickname
Join
Join
9:45 AM to 10:05 AM. Daily - Platform. This meeting has started.
9:45 AM
Daily - Platform
Now
3:00 PM to 3:15 PM. Support Daily.
3:00 PM
Support Daily
3:00 PM to 4:00 PM. Preparation for Refinement.
3:00 PM
Preparation for Refinement
4:00 PM to 5:00 PM. [Platform] Refinement 🔍.
4:00 PM
[Platform] Refinement 🔍
From your Google Calendar account: [EMAIL]
Learn more about Google Meet
Learn more
about Google Meet...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
15610
|
695
|
3
|
2026-05-11T07:04:27.033879+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778483067033_m2.jpg...
|
Firefox
|
Google Meet — Work
|
True
|
meet.google.com/landing?authuser=lukas.kovalik@jim meet.google.com/landing?authuser=lukas.kovalik@jiminny.com...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Google Meet
Close tab
New Tab
Open Google Gemini ( Google Meet
Close tab
New Tab
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Customize sidebar
Main menu
Google Meet
Meet
10:04 AM
•
Mon, May 11
Support
Report a problem
Settings
Google apps
Google Account: [EMAIL]
Meetings
Meetings
Calls
Calls
Secure video conferencing for everyone
Secure video conferencing for everyone
Connect, collaborate, and celebrate from anywhere with
Google Meet
New meeting
New meeting
Enter a code or nickname
Join
Join
9:45 AM to 10:05 AM. Daily - Platform. This meeting has started.
9:45 AM
Daily - Platform
Now
3:00 PM to 3:15 PM. Support Daily.
3:00 PM
Support Daily
3:00 PM to 4:00 PM. Preparation for Refinement.
3:00 PM
Preparation for Refinement
4:00 PM to 5:00 PM. [Platform] Refinement 🔍.
4:00 PM
[Platform] Refinement 🔍
From your Google Calendar account: [EMAIL]
Learn more about Google Meet
Learn more
about Google Meet...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Google Meet","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.016123671,"height":-0.051875472},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.27094415,"top":1.0,"width":0.004986702,"height":-0.051875472},"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.27310506,"top":1.0,"width":0.010638298,"height":-0.086193085},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"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,"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,"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,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Main menu","depth":9,"bounds":{"left":0.29039228,"top":1.0,"width":0.015957447,"height":-0.058260202},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXLink","text":"Google Meet","depth":10,"bounds":{"left":0.30767953,"top":1.0,"width":0.05900931,"height":-0.059856296},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Meet","depth":12,"bounds":{"left":0.35023272,"top":1.0,"width":0.016456118,"height":-0.06703913},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"10:04 AM","depth":10,"bounds":{"left":0.60754657,"top":1.0,"width":0.025265958,"height":-0.06823623},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":10,"bounds":{"left":0.6328125,"top":1.0,"width":0.004986702,"height":-0.06823623},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mon, May 11","depth":10,"bounds":{"left":0.6377992,"top":1.0,"width":0.03274601,"height":-0.06823623},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Support","depth":11,"bounds":{"left":0.67453456,"top":1.0,"width":0.013297873,"height":-0.061452508},"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":"Report a problem","depth":11,"bounds":{"left":0.6878325,"top":1.0,"width":0.013297873,"height":-0.061452508},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Settings","depth":11,"bounds":{"left":0.70113033,"top":1.0,"width":0.013297873,"height":-0.061452508},"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":11,"bounds":{"left":0.7150931,"top":1.0,"width":0.013297873,"height":-0.061452508},"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":"Google Account: lukas.kovalik@jiminny.com","depth":11,"bounds":{"left":0.73105055,"top":1.0,"width":0.013297873,"height":-0.061452508},"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":"Meetings","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Meetings","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Calls","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Calls","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Secure video conferencing for everyone","depth":10,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Secure video conferencing for everyone","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Connect, collaborate, and celebrate from anywhere with","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Google Meet","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New meeting","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":"AXStaticText","text":"New meeting","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Enter a code or nickname","depth":10,"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Join","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Join","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"9:45 AM to 10:05 AM. Daily - Platform. This meeting has started.","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false},{"role":"AXStaticText","text":"9:45 AM","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Daily - Platform","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Now","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"3:00 PM to 3:15 PM. Support Daily.","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3:00 PM","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Support Daily","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"3:00 PM to 4:00 PM. Preparation for Refinement.","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3:00 PM","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Preparation for Refinement","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"4:00 PM to 5:00 PM. [Platform] Refinement 🔍.","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4:00 PM","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[Platform] Refinement 🔍","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"From your Google Calendar account: lukas.kovalik@jiminny.com","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Learn more about Google Meet","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Learn more","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"about Google Meet","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-8086202985572363075
|
1734439298472096902
|
click
|
accessibility
|
NULL
|
Google Meet
Close tab
New Tab
Open Google Gemini ( Google Meet
Close tab
New Tab
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Customize sidebar
Main menu
Google Meet
Meet
10:04 AM
•
Mon, May 11
Support
Report a problem
Settings
Google apps
Google Account: [EMAIL]
Meetings
Meetings
Calls
Calls
Secure video conferencing for everyone
Secure video conferencing for everyone
Connect, collaborate, and celebrate from anywhere with
Google Meet
New meeting
New meeting
Enter a code or nickname
Join
Join
9:45 AM to 10:05 AM. Daily - Platform. This meeting has started.
9:45 AM
Daily - Platform
Now
3:00 PM to 3:15 PM. Support Daily.
3:00 PM
Support Daily
3:00 PM to 4:00 PM. Preparation for Refinement.
3:00 PM
Preparation for Refinement
4:00 PM to 5:00 PM. [Platform] Refinement 🔍.
4:00 PM
[Platform] Refinement 🔍
From your Google Calendar account: [EMAIL]
Learn more about Google Meet
Learn more
about Google Meet...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
4334
|
155
|
4
|
2026-05-07T13:27:36.086320+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778160456086_m1.jpg...
|
Claude
|
Claude
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Skip to content
Skip to content
Click to collapse
Skip to content
Skip to content
Click to collapse
⌘B
Drag to resize
Open sidebar
Chat
Cowork
Code
New chat ⌘N
New chat
⌘N
Projects
Artifacts
Customize
Pinned
Bulgarian citizenship application process for EU residents
More options for Bulgarian citizenship application process for EU residents
Dawarich location tracking project
More options for Dawarich location tracking project
Recents
View all
HubSpot rate limit implementation strategy
More options for HubSpot rate limit implementation strategy
Screenpipe retention policy code location
More options for Screenpipe retention policy code location
Viewing retention policy in screenpipe
More options for Viewing retention policy in screenpipe
Clean shot x video recording termination issue
More options for Clean shot x video recording termination issue
HubSpot rate limit handling with executeRequest
More options for HubSpot rate limit handling with executeRequest
Untitled
More options
💬 Screen pipe. Is there ability…
More options for 💬 Screen pipe. Is there ability…
SMB mount access inconsistency between Finder and iTerm
More options for SMB mount access inconsistency between Finder and iTerm
💬 What is the best switch I can…
More options for 💬 What is the best switch I can…
Permission denied on screenpipe volume
More options for Permission denied on screenpipe volume
Screenpipe sync database attachment error
More options for Screenpipe sync database attachment error
Last swimming outing with Dani
More options for Last swimming outing with Dani
Definition of incarcerated
More options for Definition of incarcerated
Chromecast remote volume buttons not working
More options for Chromecast remote volume buttons not working
Salesforce API errors with Organization and FieldDefinition queries
More options for Salesforce API errors with Organization and FieldDefinition queries
Daily activity summary from screenpipe data
More options for Daily activity summary from screenpipe data
MacBook unexpected restarts and kanji screen
More options for MacBook unexpected restarts and kanji screen
Security patch review and testing guidance
More options for Security patch review and testing guidance
Food calorie values reference
More options for Food calorie values reference
Tracking location history from last week
More options for Tracking location history from last week
Lukas Pro
Get apps and extensions
HubSpot rate limit implementation strategy, rename chat
HubSpot rate limit implementation strategy
More options for HubSpot rate limit implementation strategy
Close
Share chat
Claude finished the response
You said: So just a solution for rate limit implementation.
You said: So just a solution for rate limit implementation.
So just a solution for rate limit implementation. The situation currently is that there are some daily and secondary limits for HubSpot. I would like to make sure I never reach a 429 error rate limit. The requests can come from any flow. It can be:
updating activity (engagement, meeting, call, note)
searching for a company or contact
updating deal
patching IDs
Review what the limit is at the moment in the HubSpot documentation and then think of the solution:
where to store it
how to read it
how to work with multiple jobs
how to work with paginated requests Let's consider a situation when there are 600 opportunities to sync. What would be the flow? How would the rate limit be recognized? How would it be handled? What are the potential issues? [API usage guidelines and limits - HubSpot docs](
https://developers.hubspot.com/docs/developer-tooling/platform/usage-guidelines
https://developers.hubspot.com/docs/developer-tooling/platform/usage-guidelines
). Example of such a 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":"019dffc4-4 (truncated...). Think carefully about the implementation and potential issue and bottlenecks.
Show more
10:42
Retry
Edit
Copy
Claude responded: Current HubSpot limits (Apr 2026)
Claude responded: Current HubSpot limits (Apr 2026)
Synthesized HubSpot rate limit architecture with Redis storage and sliding window algorithms
Synthesized HubSpot rate limit architecture with Redis storage and sliding window algorithms
Current HubSpot limits (Apr 2026)
Current HubSpot limits (Apr 2026)
For privately distributed apps (which is what Jiminny presumably uses with HubSpot), the limits are layered: a per-app burst window of 100/10s on Free/Starter, 190/10s on Pro/Enterprise, or 250/10s with the API Limit Increase add-on
, plus a per-account daily cap of 250k / 625k / 1M depending on tier — shared across all private apps in the account
. The burst window is per app; the daily quota is per portal.
hubspot
hubspot
hubspot
hubspot
The Search API is special: five requests per second per account, capped at 200 records per page, with a hard 10,000-result ceiling per query
. That's the limit the 429 in your example is hitting (
secondly limit
on
/crm/v3/objects/contact/search
). It's a separate bucket from the 190/10s, and critically, search responses do not include the
X-HubSpot-RateLimit-*
headers
— you can't read remaining capacity off the response, you have to track it yourself.
hubspot
hubspot
hubspot
hubspot
Non-search endpoints return
X-HubSpot-RateLimit-Remaining
,
-Max
, and
-Interval-Milliseconds
. The daily headers are not returned for OAuth-authenticated calls
, so for those you check the account-info endpoint or maintain your own counter. There's also a soft rule: errors should stay under 5% of total daily requests
— that's enforced for marketplace listing, but it's also a sane operational target.
hubspot
hubspot
hubspot
hubspot
So you have
four buckets
to track at minimum: app-burst (10s sliding), search-secondly (1s sliding), account-daily (24h fixed, midnight in HubSpot's TZ), and per-app daily share (your own budgeting on top of the account cap).
Where to store it
Where to store it
Redis. It's the only realistic option once you have multiple queue workers — DB-backed counters serialize too much, and in-process state can't coordinate across workers. Laravel already speaks Redis natively, and you get atomic
INCR
/
EXPIRE
plus Lua scripting for true CAS semantics.
Key layout I'd use:
Copy to clipboard
hubspot:rl:burst:{portalId}:{appId} ZSET (sliding 10s)
hubspot:rl:search:{portalId} ZSET (sliding 1s)
hubspot:rl:daily:{portalId} STRING + TTL to midnight TZ
hubspot:rl:meta:{portalId} HASH (last seen headers)
The two short-window buckets are sliding-window-log (Redis ZSET, score =
microtime
, member = unique request id). Lua script removes entries older than the window, counts remaining slots, and only adds the new one if there's room — all atomic. Fixed windows are simpler but allow 2× the limit at the boundary, which on a 5/s window is brutal.
The daily bucket is a plain
INCR
with TTL set to seconds-until-midnight in
HubSpot's account timezone
, not yours — Sofia is UTC+2/+3 but your portal might be set to US Eastern. Get this once and cache it.
How to read it
How to read it
Two-phase: optimistic pre-check, authoritative post-update.
Before a call, run the Lua acquire script. If it returns "denied," sleep until a slot frees up (the script can return ms-until-next-slot) or push the job back to the queue with a delay. Don't busy-loop.
After the call, parse
X-HubSpot-RateLimit-Remaining
/
-Max
/
-Interval-Milliseconds
and store them in
hubspot:rl:meta:{portalId}
. This is your reality check — if your local counter says 50 remaining but HubSpot's header says 5, you trust HubSpot and clamp your counter. This handles clock drift, missed accounting (e.g., crashed worker that took a token but never made the request), and other apps in the same account consuming the daily budget invisibly.
For search specifically, since headers don't come back, the local counter
is
the source of truth — meaning if you ever crash mid-flight, you've under-counted. Always release tokens on connection-level failure but
not
on 429 (you really did make that request).
How to work with multiple jobs
How to work with multiple jobs
The queue layer needs to enforce concurrency separately from the rate limiter. Both work together:
Concurrency cap
via
Queue::throttle()
or a Redis semaphore — limits how many sync workers run in parallel against HubSpot. Without this, you can have 50 workers all blocked waiting for tokens, which is wasteful and creates retry storms.
Per-tenant fairness
— if you sync many Jiminny customers into different HubSpot portals, each portal has its own bucket but you still want one slow portal not to starve others. Either separate queues per portal or a fair-share scheduler.
Priority lanes
— webhook-driven updates (user-visible latency) should outrank background batch syncs. Two queues:
hubspot-priority
and
hubspot-bulk
, with priority workers taking 70% of the burst budget and bulk taking 30% (enforce via separate sub-buckets if you really want hard separation, otherwise just pull from priority first).
Backoff on 429
— respect the
Retry-After
header. If absent, exponential with jitter (e.g.,
min(2^attempt * 250ms, 30s) ± 20%
). The jitter is non-negotiable; without it, simultaneous 429s retry in lockstep and you get thundering-herd 429s on retry.
How to work with paginated requests
How to work with paginated requests
The trap is treating "fetch all" as one logical operation. Each page is its own API call and competes for tokens with everything else.
Two practical rules:
Don't hold the worker idle while paginating.
If page N takes 500ms and page N+1 needs to wait 800ms for a token, you've burned 800ms of worker time doing nothing. Instead, fetch page N, dispatch the
processing
of page N as a separate job, and queue a "fetch page N+1" job with a delay equal to the wait time. Each page becomes its own atomic unit.
Always batch where HubSpot offers it.
POST /crm/v3/objects/{type}/batch/{read|update|create}
accepts up to 100 IDs per call. For your "patching IDs" flow this is the difference between 600 calls and 6.
Walkthrough: 600 opportunities
Walkthrough: 600 opportunities
Naive flow (one PATCH per deal): 600 calls. At 190/10s that's ~32s of API time, well under daily. You'd hit burst easily without throttling. Plus likely 1-3 search calls upfront and N association calls.
Sane flow:
Identify deltas
— if you can avoid Search at all, do. Use
lastmodifieddate
filter on a single search if you must, paginate at limit=200. For 600 deals that's 3 search calls @ 5/s = ~600ms naturally throttled.
Batch read
current state —
POST /crm/v3/objects/deals/batch/read
with 100 IDs per call → 6 calls. Burst weight 6.
Compute diff
in your code (no API).
Batch update
—
POST /crm/v3/objects/deals/batch/update
with 100 per call → 6 calls.
Associations
—...
|
[{"role":"AXLink","text":& [{"role":"AXLink","text":"Skip to content","depth":14,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Skip to content","depth":15,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Click to collapse","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"⌘B","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drag to resize","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Open sidebar","depth":14,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Chat","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cowork","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New chat ⌘N","depth":15,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"New chat","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"⌘N","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Projects","depth":15,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Artifacts","depth":15,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Customize","depth":15,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Pinned","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"Bulgarian citizenship application process for EU residents","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Bulgarian citizenship application process for EU residents","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Dawarich location tracking project","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Dawarich location tracking project","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Recents","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"View all","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HubSpot rate limit implementation strategy","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for HubSpot rate limit implementation strategy","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Screenpipe retention policy code location","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Screenpipe retention policy code location","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Viewing retention policy in screenpipe","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Viewing retention policy in screenpipe","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Clean shot x video recording termination issue","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Clean shot x video recording termination issue","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HubSpot rate limit handling with executeRequest","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for HubSpot rate limit handling with executeRequest","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Untitled","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"💬 Screen pipe. Is there ability…","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for 💬 Screen pipe. Is there ability…","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"SMB mount access inconsistency between Finder and iTerm","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for SMB mount access inconsistency between Finder and iTerm","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"💬 What is the best switch I can…","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for 💬 What is the best switch I can…","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Permission denied on screenpipe volume","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Permission denied on screenpipe volume","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Screenpipe sync database attachment error","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Screenpipe sync database attachment error","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Last swimming outing with Dani","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Last swimming outing with Dani","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Definition of incarcerated","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Definition of incarcerated","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Chromecast remote volume buttons not working","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Chromecast remote volume buttons not working","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Salesforce API errors with Organization and FieldDefinition queries","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Salesforce API errors with Organization and FieldDefinition queries","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Daily activity summary from screenpipe data","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Daily activity summary from screenpipe data","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"MacBook unexpected restarts and kanji screen","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for MacBook unexpected restarts and kanji screen","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Security patch review and testing guidance","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Security patch review and testing guidance","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Food calorie values reference","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Food calorie values reference","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tracking location history from last week","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Tracking location history from last week","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Lukas Pro","depth":15,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Get apps and extensions","depth":15,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HubSpot rate limit implementation strategy, rename chat","depth":20,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"HubSpot rate limit implementation strategy","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"More options for HubSpot rate limit implementation strategy","depth":20,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":22,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Share chat","depth":22,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Claude finished the response","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"You said: So just a solution for rate limit implementation.","depth":21,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"You said: So just a solution for rate limit implementation.","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"So just a solution for rate limit implementation. The situation currently is that there are some daily and secondary limits for HubSpot. I would like to make sure I never reach a 429 error rate limit. The requests can come from any flow. It can be:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"updating activity (engagement, meeting, call, note)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"searching for a company or contact","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"updating deal","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"patching IDs\nReview what the limit is at the moment in the HubSpot documentation and then think of the solution:","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"where to store it","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"how to read it","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"how to work with multiple jobs","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"how to work with paginated requests Let's consider a situation when there are 600 opportunities to sync. What would be the flow? How would the rate limit be recognized? How would it be handled? What are the potential issues? [API usage guidelines and limits - HubSpot docs](","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"https://developers.hubspot.com/docs/developer-tooling/platform/usage-guidelines","depth":26,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://developers.hubspot.com/docs/developer-tooling/platform/usage-guidelines","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"). Example of such a error Client error:","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"POST https://api.hubapi.com/crm/v3/objects/contact/search","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"resulted in a","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"429 Too Many Requests","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT\",\"correlationId\":\"019dffc4-4 (truncated...). Think carefully about the implementation and potential issue and bottlenecks.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Show more","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:42","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Retry","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Edit","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Copy","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Claude responded: Current HubSpot limits (Apr 2026)","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Claude responded: Current HubSpot limits (Apr 2026)","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Synthesized HubSpot rate limit architecture with Redis storage and sliding window algorithms","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Synthesized HubSpot rate limit architecture with Redis storage and sliding window algorithms","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Current HubSpot limits (Apr 2026)","depth":25,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Current HubSpot limits (Apr 2026)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"For privately distributed apps (which is what Jiminny presumably uses with HubSpot), the limits are layered: a per-app burst window of 100/10s on Free/Starter, 190/10s on Pro/Enterprise, or 250/10s with the API Limit Increase add-on","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", plus a per-account daily cap of 250k / 625k / 1M depending on tier — shared across all private apps in the account","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":". The burst window is per app; the daily quota is per portal.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"hubspot","depth":27,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"hubspot","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"hubspot","depth":27,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"hubspot","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"The Search API is special: five requests per second per account, capped at 200 records per page, with a hard 10,000-result ceiling per query","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":". That's the limit the 429 in your example is hitting (","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"secondly limit","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"on","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/crm/v3/objects/contact/search","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"). It's a separate bucket from the 190/10s, and critically, search responses do not include the","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"X-HubSpot-RateLimit-*","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"headers","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— you can't read remaining capacity off the response, you have to track it yourself.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"hubspot","depth":27,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"hubspot","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"hubspot","depth":27,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"hubspot","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Non-search endpoints return","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"X-HubSpot-RateLimit-Remaining","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"-Max","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", and","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"-Interval-Milliseconds","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":". The daily headers are not returned for OAuth-authenticated calls","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", so for those you check the account-info endpoint or maintain your own counter. There's also a soft rule: errors should stay under 5% of total daily requests","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— that's enforced for marketplace listing, but it's also a sane operational target.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"hubspot","depth":27,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"hubspot","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"hubspot","depth":27,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"hubspot","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"So you have","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"four buckets","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"to track at minimum: app-burst (10s sliding), search-secondly (1s sliding), account-daily (24h fixed, midnight in HubSpot's TZ), and per-app daily share (your own budgeting on top of the account cap).","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Where to store it","depth":25,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Where to store it","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Redis. It's the only realistic option once you have multiple queue workers — DB-backed counters serialize too much, and in-process state can't coordinate across workers. Laravel already speaks Redis natively, and you get atomic","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"INCR","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"EXPIRE","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"plus Lua scripting for true CAS semantics.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Key layout I'd use:","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy to clipboard","depth":28,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"hubspot:rl:burst:{portalId}:{appId} ZSET (sliding 10s)","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"hubspot:rl:search:{portalId} ZSET (sliding 1s)","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"hubspot:rl:daily:{portalId} STRING + TTL to midnight TZ","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"hubspot:rl:meta:{portalId} HASH (last seen headers)","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"The two short-window buckets are sliding-window-log (Redis ZSET, score =","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"microtime","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", member = unique request id). Lua script removes entries older than the window, counts remaining slots, and only adds the new one if there's room — all atomic. Fixed windows are simpler but allow 2× the limit at the boundary, which on a 5/s window is brutal.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"The daily bucket is a plain","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"INCR","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"with TTL set to seconds-until-midnight in","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HubSpot's account timezone","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", not yours — Sofia is UTC+2/+3 but your portal might be set to US Eastern. Get this once and cache it.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"How to read it","depth":25,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"How to read it","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Two-phase: optimistic pre-check, authoritative post-update.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Before a call, run the Lua acquire script. If it returns \"denied,\" sleep until a slot frees up (the script can return ms-until-next-slot) or push the job back to the queue with a delay. Don't busy-loop.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"After the call, parse","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"X-HubSpot-RateLimit-Remaining","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"-Max","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"-Interval-Milliseconds","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"and store them in","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"hubspot:rl:meta:{portalId}","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":". This is your reality check — if your local counter says 50 remaining but HubSpot's header says 5, you trust HubSpot and clamp your counter. This handles clock drift, missed accounting (e.g., crashed worker that took a token but never made the request), and other apps in the same account consuming the daily budget invisibly.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"For search specifically, since headers don't come back, the local counter","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"is","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"the source of truth — meaning if you ever crash mid-flight, you've under-counted. Always release tokens on connection-level failure but","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"not","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"on 429 (you really did make that request).","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"How to work with multiple jobs","depth":25,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"How to work with multiple jobs","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"The queue layer needs to enforce concurrency separately from the rate limiter. Both work together:","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Concurrency cap","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"via","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Queue::throttle()","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"or a Redis semaphore — limits how many sync workers run in parallel against HubSpot. Without this, you can have 50 workers all blocked waiting for tokens, which is wasteful and creates retry storms.","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Per-tenant fairness","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— if you sync many Jiminny customers into different HubSpot portals, each portal has its own bucket but you still want one slow portal not to starve others. Either separate queues per portal or a fair-share scheduler.","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Priority lanes","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— webhook-driven updates (user-visible latency) should outrank background batch syncs. Two queues:","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"hubspot-priority","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"and","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"hubspot-bulk","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", with priority workers taking 70% of the burst budget and bulk taking 30% (enforce via separate sub-buckets if you really want hard separation, otherwise just pull from priority first).","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Backoff on 429","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— respect the","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Retry-After","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"header. If absent, exponential with jitter (e.g.,","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"min(2^attempt * 250ms, 30s) ± 20%","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"). The jitter is non-negotiable; without it, simultaneous 429s retry in lockstep and you get thundering-herd 429s on retry.","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"How to work with paginated requests","depth":25,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"How to work with paginated requests","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"The trap is treating \"fetch all\" as one logical operation. Each page is its own API call and competes for tokens with everything else.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Two practical rules:","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Don't hold the worker idle while paginating.","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"If page N takes 500ms and page N+1 needs to wait 800ms for a token, you've burned 800ms of worker time doing nothing. Instead, fetch page N, dispatch the","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"processing","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"of page N as a separate job, and queue a \"fetch page N+1\" job with a delay equal to the wait time. Each page becomes its own atomic unit.","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Always batch where HubSpot offers it.","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"POST /crm/v3/objects/{type}/batch/{read|update|create}","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"accepts up to 100 IDs per call. For your \"patching IDs\" flow this is the difference between 600 calls and 6.","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Walkthrough: 600 opportunities","depth":25,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Walkthrough: 600 opportunities","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Naive flow (one PATCH per deal): 600 calls. At 190/10s that's ~32s of API time, well under daily. You'd hit burst easily without throttling. Plus likely 1-3 search calls upfront and N association calls.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sane flow:","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Identify deltas","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— if you can avoid Search at all, do. Use","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"lastmodifieddate","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"filter on a single search if you must, paginate at limit=200. For 600 deals that's 3 search calls @ 5/s = ~600ms naturally throttled.","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Batch read","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"current state —","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"POST /crm/v3/objects/deals/batch/read","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"with 100 IDs per call → 6 calls. Burst weight 6.","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Compute diff","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"in your code (no API).","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Batch update","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"—","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"POST /crm/v3/objects/deals/batch/update","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"with 100 per call → 6 calls.","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Associations","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"—","depth":27,"on_screen":false,"role_description":"text"}]...
|
-8084795883996383194
|
3624552675969423444
|
visual_change
|
accessibility
|
NULL
|
Skip to content
Skip to content
Click to collapse
Skip to content
Skip to content
Click to collapse
⌘B
Drag to resize
Open sidebar
Chat
Cowork
Code
New chat ⌘N
New chat
⌘N
Projects
Artifacts
Customize
Pinned
Bulgarian citizenship application process for EU residents
More options for Bulgarian citizenship application process for EU residents
Dawarich location tracking project
More options for Dawarich location tracking project
Recents
View all
HubSpot rate limit implementation strategy
More options for HubSpot rate limit implementation strategy
Screenpipe retention policy code location
More options for Screenpipe retention policy code location
Viewing retention policy in screenpipe
More options for Viewing retention policy in screenpipe
Clean shot x video recording termination issue
More options for Clean shot x video recording termination issue
HubSpot rate limit handling with executeRequest
More options for HubSpot rate limit handling with executeRequest
Untitled
More options
💬 Screen pipe. Is there ability…
More options for 💬 Screen pipe. Is there ability…
SMB mount access inconsistency between Finder and iTerm
More options for SMB mount access inconsistency between Finder and iTerm
💬 What is the best switch I can…
More options for 💬 What is the best switch I can…
Permission denied on screenpipe volume
More options for Permission denied on screenpipe volume
Screenpipe sync database attachment error
More options for Screenpipe sync database attachment error
Last swimming outing with Dani
More options for Last swimming outing with Dani
Definition of incarcerated
More options for Definition of incarcerated
Chromecast remote volume buttons not working
More options for Chromecast remote volume buttons not working
Salesforce API errors with Organization and FieldDefinition queries
More options for Salesforce API errors with Organization and FieldDefinition queries
Daily activity summary from screenpipe data
More options for Daily activity summary from screenpipe data
MacBook unexpected restarts and kanji screen
More options for MacBook unexpected restarts and kanji screen
Security patch review and testing guidance
More options for Security patch review and testing guidance
Food calorie values reference
More options for Food calorie values reference
Tracking location history from last week
More options for Tracking location history from last week
Lukas Pro
Get apps and extensions
HubSpot rate limit implementation strategy, rename chat
HubSpot rate limit implementation strategy
More options for HubSpot rate limit implementation strategy
Close
Share chat
Claude finished the response
You said: So just a solution for rate limit implementation.
You said: So just a solution for rate limit implementation.
So just a solution for rate limit implementation. The situation currently is that there are some daily and secondary limits for HubSpot. I would like to make sure I never reach a 429 error rate limit. The requests can come from any flow. It can be:
updating activity (engagement, meeting, call, note)
searching for a company or contact
updating deal
patching IDs
Review what the limit is at the moment in the HubSpot documentation and then think of the solution:
where to store it
how to read it
how to work with multiple jobs
how to work with paginated requests Let's consider a situation when there are 600 opportunities to sync. What would be the flow? How would the rate limit be recognized? How would it be handled? What are the potential issues? [API usage guidelines and limits - HubSpot docs](
https://developers.hubspot.com/docs/developer-tooling/platform/usage-guidelines
https://developers.hubspot.com/docs/developer-tooling/platform/usage-guidelines
). Example of such a 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":"019dffc4-4 (truncated...). Think carefully about the implementation and potential issue and bottlenecks.
Show more
10:42
Retry
Edit
Copy
Claude responded: Current HubSpot limits (Apr 2026)
Claude responded: Current HubSpot limits (Apr 2026)
Synthesized HubSpot rate limit architecture with Redis storage and sliding window algorithms
Synthesized HubSpot rate limit architecture with Redis storage and sliding window algorithms
Current HubSpot limits (Apr 2026)
Current HubSpot limits (Apr 2026)
For privately distributed apps (which is what Jiminny presumably uses with HubSpot), the limits are layered: a per-app burst window of 100/10s on Free/Starter, 190/10s on Pro/Enterprise, or 250/10s with the API Limit Increase add-on
, plus a per-account daily cap of 250k / 625k / 1M depending on tier — shared across all private apps in the account
. The burst window is per app; the daily quota is per portal.
hubspot
hubspot
hubspot
hubspot
The Search API is special: five requests per second per account, capped at 200 records per page, with a hard 10,000-result ceiling per query
. That's the limit the 429 in your example is hitting (
secondly limit
on
/crm/v3/objects/contact/search
). It's a separate bucket from the 190/10s, and critically, search responses do not include the
X-HubSpot-RateLimit-*
headers
— you can't read remaining capacity off the response, you have to track it yourself.
hubspot
hubspot
hubspot
hubspot
Non-search endpoints return
X-HubSpot-RateLimit-Remaining
,
-Max
, and
-Interval-Milliseconds
. The daily headers are not returned for OAuth-authenticated calls
, so for those you check the account-info endpoint or maintain your own counter. There's also a soft rule: errors should stay under 5% of total daily requests
— that's enforced for marketplace listing, but it's also a sane operational target.
hubspot
hubspot
hubspot
hubspot
So you have
four buckets
to track at minimum: app-burst (10s sliding), search-secondly (1s sliding), account-daily (24h fixed, midnight in HubSpot's TZ), and per-app daily share (your own budgeting on top of the account cap).
Where to store it
Where to store it
Redis. It's the only realistic option once you have multiple queue workers — DB-backed counters serialize too much, and in-process state can't coordinate across workers. Laravel already speaks Redis natively, and you get atomic
INCR
/
EXPIRE
plus Lua scripting for true CAS semantics.
Key layout I'd use:
Copy to clipboard
hubspot:rl:burst:{portalId}:{appId} ZSET (sliding 10s)
hubspot:rl:search:{portalId} ZSET (sliding 1s)
hubspot:rl:daily:{portalId} STRING + TTL to midnight TZ
hubspot:rl:meta:{portalId} HASH (last seen headers)
The two short-window buckets are sliding-window-log (Redis ZSET, score =
microtime
, member = unique request id). Lua script removes entries older than the window, counts remaining slots, and only adds the new one if there's room — all atomic. Fixed windows are simpler but allow 2× the limit at the boundary, which on a 5/s window is brutal.
The daily bucket is a plain
INCR
with TTL set to seconds-until-midnight in
HubSpot's account timezone
, not yours — Sofia is UTC+2/+3 but your portal might be set to US Eastern. Get this once and cache it.
How to read it
How to read it
Two-phase: optimistic pre-check, authoritative post-update.
Before a call, run the Lua acquire script. If it returns "denied," sleep until a slot frees up (the script can return ms-until-next-slot) or push the job back to the queue with a delay. Don't busy-loop.
After the call, parse
X-HubSpot-RateLimit-Remaining
/
-Max
/
-Interval-Milliseconds
and store them in
hubspot:rl:meta:{portalId}
. This is your reality check — if your local counter says 50 remaining but HubSpot's header says 5, you trust HubSpot and clamp your counter. This handles clock drift, missed accounting (e.g., crashed worker that took a token but never made the request), and other apps in the same account consuming the daily budget invisibly.
For search specifically, since headers don't come back, the local counter
is
the source of truth — meaning if you ever crash mid-flight, you've under-counted. Always release tokens on connection-level failure but
not
on 429 (you really did make that request).
How to work with multiple jobs
How to work with multiple jobs
The queue layer needs to enforce concurrency separately from the rate limiter. Both work together:
Concurrency cap
via
Queue::throttle()
or a Redis semaphore — limits how many sync workers run in parallel against HubSpot. Without this, you can have 50 workers all blocked waiting for tokens, which is wasteful and creates retry storms.
Per-tenant fairness
— if you sync many Jiminny customers into different HubSpot portals, each portal has its own bucket but you still want one slow portal not to starve others. Either separate queues per portal or a fair-share scheduler.
Priority lanes
— webhook-driven updates (user-visible latency) should outrank background batch syncs. Two queues:
hubspot-priority
and
hubspot-bulk
, with priority workers taking 70% of the burst budget and bulk taking 30% (enforce via separate sub-buckets if you really want hard separation, otherwise just pull from priority first).
Backoff on 429
— respect the
Retry-After
header. If absent, exponential with jitter (e.g.,
min(2^attempt * 250ms, 30s) ± 20%
). The jitter is non-negotiable; without it, simultaneous 429s retry in lockstep and you get thundering-herd 429s on retry.
How to work with paginated requests
How to work with paginated requests
The trap is treating "fetch all" as one logical operation. Each page is its own API call and competes for tokens with everything else.
Two practical rules:
Don't hold the worker idle while paginating.
If page N takes 500ms and page N+1 needs to wait 800ms for a token, you've burned 800ms of worker time doing nothing. Instead, fetch page N, dispatch the
processing
of page N as a separate job, and queue a "fetch page N+1" job with a delay equal to the wait time. Each page becomes its own atomic unit.
Always batch where HubSpot offers it.
POST /crm/v3/objects/{type}/batch/{read|update|create}
accepts up to 100 IDs per call. For your "patching IDs" flow this is the difference between 600 calls and 6.
Walkthrough: 600 opportunities
Walkthrough: 600 opportunities
Naive flow (one PATCH per deal): 600 calls. At 190/10s that's ~32s of API time, well under daily. You'd hit burst easily without throttling. Plus likely 1-3 search calls upfront and N association calls.
Sane flow:
Identify deltas
— if you can avoid Search at all, do. Use
lastmodifieddate
filter on a single search if you must, paginate at limit=200. For 600 deals that's 3 search calls @ 5/s = ~600ms naturally throttled.
Batch read
current state —
POST /crm/v3/objects/deals/batch/read
with 100 IDs per call → 6 calls. Burst weight 6.
Compute diff
in your code (no API).
Batch update
—
POST /crm/v3/objects/deals/batch/update
with 100 per call → 6 calls.
Associations
—...
|
4332
|
NULL
|
NULL
|
NULL
|
|
23990
|
1005
|
25
|
2026-05-12T08:32:40.491608+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-12/1778 /Users/lukas/.screenpipe/data/data/2026-05-12/1778574760491_m2.jpg...
|
PhpStorm
|
faVsco.js – console [EU]
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhostormFV faVsco.jsProiect‹> Untitled Diaaram. PhostormFV faVsco.jsProiect‹> Untitled Diaaram.xmlius vetur.contia.isM+ WEBHOOK FILTERING_ MPLEM>1h External Libraries)v E° Scratches and Consolesv Datahase ConsolesV AEUA console [EU)A DEAL RISKS [EU]A DI (EU]A EU (EU]v Ajiminny@localhost& console uiminhy @localno& Ul Uiminny@localnostA HS local [liminny@localhcA SF [iiminny@localhost]& zoho dev [iiminny@localhV & PROD& console [PROD1A console 1 [PROD]& DI PROD> ДOA• A PAiLPA PRODV A STAGING& console STAGNG¿ console STAGNGIuranus STAGINGI→ Extensionsm ScratchesViewINavicareCodeLaravelTOOISWindowmelp°9 JY-20725-handle-HS-search-rate-limit• suppont Dally • In 3n zomHandleHubspotRateLimitTest v100% 5• Tue 12 May 11:32:40C) AutomatedReportGenerated.onp© PlaybackController.php=custom.log=laravel.logA SF (jiminny@localhost]4 HS_local [jiminny@localhost]# console [PRol)« console [EU] X© AutomatedReportResult.php xA console [STAGING]carbon/nucl sreqvescea.au* @pnopenty Carbon/null Sgenerated_at18e1e1AV* donopenc carbon null ssentau* donopenc carboninull screaceaau* doropen caroon nucl supdaceaac* @propertu-read |Jiminnu Models\AutomatedReport Sreport*doropertu-read Automatedreportresult null Sparent* @propertu-read |Illuminate Database\Eloquent\Collection<int. AutomatedReportResult> Schildren33 (09class AutomatedReportresult extends Modeluse Reautresuuids* Status constantspublic const int STATUS_DEFAULT = 0;public const int STATUS_REQUESTED = 1;16 usagespublic const int STATUS_GENERATED = 2;pubulc const int sialus_seNl = s,public const int STATUS_FAILED = 4;1615=161616171618161916201621.162216241625162616271628—16291630163116321633163*Poncon conctante116561637- 1639 Vpublic const int REASON_DEFAULT = 0:Outoutitiminnv automated renort results Xfw 3 rowsvMid 7Muuid CUUID with time-low a…7 ÷ Mrenort id Y240677/252c-4157-4408-87de-ca8h700070a4|cascadePlanhat Event PlaybacTx: AutovPlavaroundliminnyfind planhat event playback visitedFRuM stages sul business process stages oos•1<o>I.n. Unoos.stade 1d = s.10WHERE bos.business process 1d = 6024AND s.crm_provider_id = 'contractsent';028 A9 A25 V 3 X 105 ^ThoughtsSearched olavback *visitedivisited."olavback in ~/fiminnvlaoolselect * from stages where id IN 16352.20612.18281.7344.16378.16309.5036.15223.14535.6293.12098.1160701SELECT * FROM teams WHERE name LIKE '%Pulsar Group%'; # 472, 380, 15138, [EMAIL] * from playbooks where team_id = 472; # event 226147SELECT * EROM nlavhook cateaonies WHERE nlavhook id = 2288.SELECT * FROM crm_fields WHERE id = 226147;SELECT * EROM com field values WHERE com field id = 2261475CCISCT + SP0M eom confiaunatione MHEpE id - 7801SELECTCONCAT(u.id, CASE WHEN u.id = t.owner id THEN ' (owner)' ELSE !• END) AS user idU.enallsa.*t.owner 1d FkuM social accounts saJOIN users u on u.id = sa.sociable idJOIN teams t 1.n<->1: on t.id = u.team idWHERE u.team id = 472 and sa.provider = 'salesforce' :Found it in PlaybackController.php :NorlwwrkconrelllernhlokostiraLocation:Plavbackcontroller.0no:95-168oho.*Cendina InlavbackVicitedi event to Planhat without clowina theselect * from actavities where id = 58081273;select * from automated_report_results where media type = 'pdf' and status = 2;deterlfn = Sthis-solanhatService-strack(Ask anything (&AL)<> Code SWE-1.6Services+,o,ctv O DatabaseV dEUconsole 3 gv Aliminnv@localhostAHSocal 1s 665 msASFv APRODA console 1s 225 ms# STAGINGIconsole…Docker@: -M name Y485 Loss Analysis - 1 Jan - 27 Nov 2025 - Delivery, Sales Development259 e1a9321d-1c27-4ea8-8f4a-C90fa3da431e613 a944c496-7432-4237-a935-5d1ab3086c643 Exec Summary - 24 - 1 Dec 2025 - A21* !media type Yparent id Y÷ Mstatus YM reason YI payloadpdf0 {"team_id":137,"request_id":"b776253c-4153-44e8-87de-cipdf0 {"team_id":73,"request id":"e1a9321d-1c27-4ea8-8f4a-c9|563 Coaching Profiles - 28 - 31 Jan 2026 - BDR - EMEA, BOR - Nonth Amenica, UK team, Sweden Team, Nonth Amenica team, Nonway Team, Nethenlands Team, Finland Team, Denmank team, DACH team0 {"team_id":269."request_ id"."a944c496-7432-4237-a935-51WN Windsurf Toams 1620-17UTF.8I...
|
NULL
|
-8082046365625924245
|
NULL
|
click
|
ocr
|
NULL
|
PhostormFV faVsco.jsProiect‹> Untitled Diaaram. PhostormFV faVsco.jsProiect‹> Untitled Diaaram.xmlius vetur.contia.isM+ WEBHOOK FILTERING_ MPLEM>1h External Libraries)v E° Scratches and Consolesv Datahase ConsolesV AEUA console [EU)A DEAL RISKS [EU]A DI (EU]A EU (EU]v Ajiminny@localhost& console uiminhy @localno& Ul Uiminny@localnostA HS local [liminny@localhcA SF [iiminny@localhost]& zoho dev [iiminny@localhV & PROD& console [PROD1A console 1 [PROD]& DI PROD> ДOA• A PAiLPA PRODV A STAGING& console STAGNG¿ console STAGNGIuranus STAGINGI→ Extensionsm ScratchesViewINavicareCodeLaravelTOOISWindowmelp°9 JY-20725-handle-HS-search-rate-limit• suppont Dally • In 3n zomHandleHubspotRateLimitTest v100% 5• Tue 12 May 11:32:40C) AutomatedReportGenerated.onp© PlaybackController.php=custom.log=laravel.logA SF (jiminny@localhost]4 HS_local [jiminny@localhost]# console [PRol)« console [EU] X© AutomatedReportResult.php xA console [STAGING]carbon/nucl sreqvescea.au* @pnopenty Carbon/null Sgenerated_at18e1e1AV* donopenc carbon null ssentau* donopenc carboninull screaceaau* doropen caroon nucl supdaceaac* @propertu-read |Jiminnu Models\AutomatedReport Sreport*doropertu-read Automatedreportresult null Sparent* @propertu-read |Illuminate Database\Eloquent\Collection<int. AutomatedReportResult> Schildren33 (09class AutomatedReportresult extends Modeluse Reautresuuids* Status constantspublic const int STATUS_DEFAULT = 0;public const int STATUS_REQUESTED = 1;16 usagespublic const int STATUS_GENERATED = 2;pubulc const int sialus_seNl = s,public const int STATUS_FAILED = 4;1615=161616171618161916201621.162216241625162616271628—16291630163116321633163*Poncon conctante116561637- 1639 Vpublic const int REASON_DEFAULT = 0:Outoutitiminnv automated renort results Xfw 3 rowsvMid 7Muuid CUUID with time-low a…7 ÷ Mrenort id Y240677/252c-4157-4408-87de-ca8h700070a4|cascadePlanhat Event PlaybacTx: AutovPlavaroundliminnyfind planhat event playback visitedFRuM stages sul business process stages oos•1<o>I.n. Unoos.stade 1d = s.10WHERE bos.business process 1d = 6024AND s.crm_provider_id = 'contractsent';028 A9 A25 V 3 X 105 ^ThoughtsSearched olavback *visitedivisited."olavback in ~/fiminnvlaoolselect * from stages where id IN 16352.20612.18281.7344.16378.16309.5036.15223.14535.6293.12098.1160701SELECT * FROM teams WHERE name LIKE '%Pulsar Group%'; # 472, 380, 15138, [EMAIL] * from playbooks where team_id = 472; # event 226147SELECT * EROM nlavhook cateaonies WHERE nlavhook id = 2288.SELECT * FROM crm_fields WHERE id = 226147;SELECT * EROM com field values WHERE com field id = 2261475CCISCT + SP0M eom confiaunatione MHEpE id - 7801SELECTCONCAT(u.id, CASE WHEN u.id = t.owner id THEN ' (owner)' ELSE !• END) AS user idU.enallsa.*t.owner 1d FkuM social accounts saJOIN users u on u.id = sa.sociable idJOIN teams t 1.n<->1: on t.id = u.team idWHERE u.team id = 472 and sa.provider = 'salesforce' :Found it in PlaybackController.php :NorlwwrkconrelllernhlokostiraLocation:Plavbackcontroller.0no:95-168oho.*Cendina InlavbackVicitedi event to Planhat without clowina theselect * from actavities where id = 58081273;select * from automated_report_results where media type = 'pdf' and status = 2;deterlfn = Sthis-solanhatService-strack(Ask anything (&AL)<> Code SWE-1.6Services+,o,ctv O DatabaseV dEUconsole 3 gv Aliminnv@localhostAHSocal 1s 665 msASFv APRODA console 1s 225 ms# STAGINGIconsole…Docker@: -M name Y485 Loss Analysis - 1 Jan - 27 Nov 2025 - Delivery, Sales Development259 e1a9321d-1c27-4ea8-8f4a-C90fa3da431e613 a944c496-7432-4237-a935-5d1ab3086c643 Exec Summary - 24 - 1 Dec 2025 - A21* !media type Yparent id Y÷ Mstatus YM reason YI payloadpdf0 {"team_id":137,"request_id":"b776253c-4153-44e8-87de-cipdf0 {"team_id":73,"request id":"e1a9321d-1c27-4ea8-8f4a-c9|563 Coaching Profiles - 28 - 31 Jan 2026 - BDR - EMEA, BOR - Nonth Amenica, UK team, Sweden Team, Nonth Amenica team, Nonway Team, Nethenlands Team, Finland Team, Denmank team, DACH team0 {"team_id":269."request_ id"."a944c496-7432-4237-a935-51WN Windsurf Toams 1620-17UTF.8I...
|
23989
|
NULL
|
NULL
|
NULL
|
|
16283
|
730
|
9
|
2026-05-11T08:36:55.028828+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778488615028_m1.jpg...
|
PhpStorm
|
faVsco.js – PaginationState.php
|
True
|
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
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot\Pagination;
class PaginationState
{
public function __construct(
public int $requestCount = 0,
public int $totalRecords = 0,
public int $lastTokenCheck = 0,
public ?string $lastRecordId = null,
public float $startTime = 0.0,
public int $total = 0,
public int $offset = 0
) {
if ($this->startTime === 0.0) {
$this->startTime = microtime(true);
}
if ($this->lastTokenCheck === 0) {
$this->lastTokenCheck = now()->getTimestamp();
}
}
public function incrementRequestCount(): void
{
$this->requestCount++;
}
public function incrementTotalRecords(): void
{
$this->totalRecords++;
}
public function updateLastTokenCheck(): void
{
$this->lastTokenCheck = now()->getTimestamp();
}
public function setTotal(int $total): void
{
if ($this->total === 0) {
$this->total = $total;
}
}
public function updateLastRecordId(?string $lastRecordId): void
{
if ($lastRecordId !== null) {
$this->lastRecordId = $lastRecordId;
}
}
public function setOffset(int $offset): void
{
$this->offset = $offset;
}
public function shouldLogProgress(): bool
{
return $this->requestCount > 0 && $this->requestCount % PaginationConfig::PAGINATION_LOG_FREQUENCY === 0;
}
public function hasReachedSafetyLimit(): bool
{
return $this->requestCount >= PaginationConfig::LOOP_SAFETY_LIMIT;
}
public function shouldValidateToken(): bool
{
$currentTime = now()->getTimestamp();
return $this->requestCount > 0 && ($currentTime - $this->lastTokenCheck) >= PaginationConfig::TOKEN_CHECK_INTERVAL;
}
public function getElapsedSeconds(): float
{
return microtime(true) - $this->startTime;
}
}
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"}...
|
[{"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":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot\\Pagination;\n\nclass PaginationState\n{\n public function __construct(\n public int $requestCount = 0,\n public int $totalRecords = 0,\n public int $lastTokenCheck = 0,\n public ?string $lastRecordId = null,\n public float $startTime = 0.0,\n public int $total = 0,\n public int $offset = 0\n ) {\n if ($this->startTime === 0.0) {\n $this->startTime = microtime(true);\n }\n if ($this->lastTokenCheck === 0) {\n $this->lastTokenCheck = now()->getTimestamp();\n }\n }\n\n public function incrementRequestCount(): void\n {\n $this->requestCount++;\n }\n\n public function incrementTotalRecords(): void\n {\n $this->totalRecords++;\n }\n\n public function updateLastTokenCheck(): void\n {\n $this->lastTokenCheck = now()->getTimestamp();\n }\n\n public function setTotal(int $total): void\n {\n if ($this->total === 0) {\n $this->total = $total;\n }\n }\n\n public function updateLastRecordId(?string $lastRecordId): void\n {\n if ($lastRecordId !== null) {\n $this->lastRecordId = $lastRecordId;\n }\n }\n\n public function setOffset(int $offset): void\n {\n $this->offset = $offset;\n }\n\n public function shouldLogProgress(): bool\n {\n return $this->requestCount > 0 && $this->requestCount % PaginationConfig::PAGINATION_LOG_FREQUENCY === 0;\n }\n\n public function hasReachedSafetyLimit(): bool\n {\n return $this->requestCount >= PaginationConfig::LOOP_SAFETY_LIMIT;\n }\n\n public function shouldValidateToken(): bool\n {\n $currentTime = now()->getTimestamp();\n\n return $this->requestCount > 0 && ($currentTime - $this->lastTokenCheck) >= PaginationConfig::TOKEN_CHECK_INTERVAL;\n }\n\n public function getElapsedSeconds(): float\n {\n return microtime(true) - $this->startTime;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot\\Pagination;\n\nclass PaginationState\n{\n public function __construct(\n public int $requestCount = 0,\n public int $totalRecords = 0,\n public int $lastTokenCheck = 0,\n public ?string $lastRecordId = null,\n public float $startTime = 0.0,\n public int $total = 0,\n public int $offset = 0\n ) {\n if ($this->startTime === 0.0) {\n $this->startTime = microtime(true);\n }\n if ($this->lastTokenCheck === 0) {\n $this->lastTokenCheck = now()->getTimestamp();\n }\n }\n\n public function incrementRequestCount(): void\n {\n $this->requestCount++;\n }\n\n public function incrementTotalRecords(): void\n {\n $this->totalRecords++;\n }\n\n public function updateLastTokenCheck(): void\n {\n $this->lastTokenCheck = now()->getTimestamp();\n }\n\n public function setTotal(int $total): void\n {\n if ($this->total === 0) {\n $this->total = $total;\n }\n }\n\n public function updateLastRecordId(?string $lastRecordId): void\n {\n if ($lastRecordId !== null) {\n $this->lastRecordId = $lastRecordId;\n }\n }\n\n public function setOffset(int $offset): void\n {\n $this->offset = $offset;\n }\n\n public function shouldLogProgress(): bool\n {\n return $this->requestCount > 0 && $this->requestCount % PaginationConfig::PAGINATION_LOG_FREQUENCY === 0;\n }\n\n public function hasReachedSafetyLimit(): bool\n {\n return $this->requestCount >= PaginationConfig::LOOP_SAFETY_LIMIT;\n }\n\n public function shouldValidateToken(): bool\n {\n $currentTime = now()->getTimestamp();\n\n return $this->requestCount > 0 && ($currentTime - $this->lastTokenCheck) >= PaginationConfig::TOKEN_CHECK_INTERVAL;\n }\n\n public function getElapsedSeconds(): float\n {\n return microtime(true) - $this->startTime;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"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}]...
|
-8081366442047192494
|
2071413224620920803
|
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
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot\Pagination;
class PaginationState
{
public function __construct(
public int $requestCount = 0,
public int $totalRecords = 0,
public int $lastTokenCheck = 0,
public ?string $lastRecordId = null,
public float $startTime = 0.0,
public int $total = 0,
public int $offset = 0
) {
if ($this->startTime === 0.0) {
$this->startTime = microtime(true);
}
if ($this->lastTokenCheck === 0) {
$this->lastTokenCheck = now()->getTimestamp();
}
}
public function incrementRequestCount(): void
{
$this->requestCount++;
}
public function incrementTotalRecords(): void
{
$this->totalRecords++;
}
public function updateLastTokenCheck(): void
{
$this->lastTokenCheck = now()->getTimestamp();
}
public function setTotal(int $total): void
{
if ($this->total === 0) {
$this->total = $total;
}
}
public function updateLastRecordId(?string $lastRecordId): void
{
if ($lastRecordId !== null) {
$this->lastRecordId = $lastRecordId;
}
}
public function setOffset(int $offset): void
{
$this->offset = $offset;
}
public function shouldLogProgress(): bool
{
return $this->requestCount > 0 && $this->requestCount % PaginationConfig::PAGINATION_LOG_FREQUENCY === 0;
}
public function hasReachedSafetyLimit(): bool
{
return $this->requestCount >= PaginationConfig::LOOP_SAFETY_LIMIT;
}
public function shouldValidateToken(): bool
{
$currentTime = now()->getTimestamp();
return $this->requestCount > 0 && ($currentTime - $this->lastTokenCheck) >= PaginationConfig::TOKEN_CHECK_INTERVAL;
}
public function getElapsedSeconds(): float
{
return microtime(true) - $this->startTime;
}
}
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"}...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
2520
|
105
|
30
|
2026-05-07T11:23:30.089296+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778153010089_m1.jpg...
|
Claude
|
Claude
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Skip to content
Skip to content
Click to collapse
Skip to content
Skip to content
Click to collapse
⌘B
Drag to resize
Open sidebar
Chat
Cowork
Code
New chat ⌘N
New chat
⌘N
Projects
Artifacts
Customize
Pinned
Bulgarian citizenship application process for EU residents
More options for Bulgarian citizenship application process for EU residents
Dawarich location tracking project
More options for Dawarich location tracking project
Recents
View all
HubSpot rate limit implementation strategy
More options for HubSpot rate limit implementation strategy
Screenpipe retention policy code location
More options for Screenpipe retention policy code location
Viewing retention policy in screenpipe
More options for Viewing retention policy in screenpipe
Clean shot x video recording termination issue
More options for Clean shot x video recording termination issue
HubSpot rate limit handling with executeRequest
More options for HubSpot rate limit handling with executeRequest
Untitled
More options
💬 Screen pipe. Is there ability…
More options for 💬 Screen pipe. Is there ability…
SMB mount access inconsistency between Finder and iTerm
More options for SMB mount access inconsistency between Finder and iTerm
💬 What is the best switch I can…
More options for 💬 What is the best switch I can…
Permission denied on screenpipe volume
More options for Permission denied on screenpipe volume
Screenpipe sync database attachment error
More options for Screenpipe sync database attachment error
Last swimming outing with Dani
More options for Last swimming outing with Dani
Definition of incarcerated
More options for Definition of incarcerated
Chromecast remote volume buttons not working
More options for Chromecast remote volume buttons not working
Salesforce API errors with Organization and FieldDefinition queries
More options for Salesforce API errors with Organization and FieldDefinition queries
Daily activity summary from screenpipe data
More options for Daily activity summary from screenpipe data
MacBook unexpected restarts and kanji screen
More options for MacBook unexpected restarts and kanji screen
Security patch review and testing guidance
More options for Security patch review and testing guidance
Food calorie values reference
More options for Food calorie values reference
Tracking location history from last week
More options for Tracking location history from last week
Lukas Pro
Get apps and extensions
HubSpot rate limit implementation strategy, rename chat
HubSpot rate limit implementation strategy
More options for HubSpot rate limit implementation strategy
Open sidebar
Share chat
Claude finished the response
You said: So just a solution for rate limit implementation.
You said: So just a solution for rate limit implementation.
So just a solution for rate limit implementation. The situation currently is that there are some daily and secondary limits for HubSpot. I would like to make sure I never reach a 429 error rate limit. The requests can come from any flow. It can be:
updating activity (engagement, meeting, call, note)
searching for a company or contact
updating deal
patching IDs
Review what the limit is at the moment in the HubSpot documentation and then think of the solution:
where to store it
how to read it
how to work with multiple jobs
how to work with paginated requests Let's consider a situation when there are 600 opportunities to sync. What would be the flow? How would the rate limit be recognized? How would it be handled? What are the potential issues? [API usage guidelines and limits - HubSpot docs](
https://developers.hubspot.com/docs/developer-tooling/platform/usage-guidelines
https://developers.hubspot.com/docs/developer-tooling/platform/usage-guidelines
). Example of such a 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":"019dffc4-4 (truncated...). Think carefully about the implementation and potential issue and bottlenecks.
Show more
10:42
Retry
Edit
Copy
Claude responded: Current HubSpot limits (Apr 2026)
Claude responded: Current HubSpot limits (Apr 2026)
Synthesized HubSpot rate limit architecture with Redis storage and sliding window algorithms
Synthesized HubSpot rate limit architecture with Redis storage and sliding window algorithms
Current HubSpot limits (Apr 2026)
Current HubSpot limits (Apr 2026)
For privately distributed apps (which is what Jiminny presumably uses with HubSpot), the limits are layered: a per-app burst window of 100/10s on Free/Starter, 190/10s on Pro/Enterprise, or 250/10s with the API Limit Increase add-on
, plus a per-account daily cap of 250k / 625k / 1M depending on tier — shared across all private apps in the account
. The burst window is per app; the daily quota is per portal.
hubspot
hubspot
hubspot
hubspot
The Search API is special: five requests per second per account, capped at 200 records per page, with a hard 10,000-result ceiling per query
. That's the limit the 429 in your example is hitting (
secondly limit
on
/crm/v3/objects/contact/search
). It's a separate bucket from the 190/10s, and critically, search responses do not include the
X-HubSpot-RateLimit-*
headers
— you can't read remaining capacity off the response, you have to track it yourself.
hubspot
hubspot
hubspot
hubspot
Non-search endpoints return
X-HubSpot-RateLimit-Remaining
,
-Max
, and
-Interval-Milliseconds
. The daily headers are not returned for OAuth-authenticated calls
, so for those you check the account-info endpoint or maintain your own counter. There's also a soft rule: errors should stay under 5% of total daily requests
— that's enforced for marketplace listing, but it's also a sane operational target.
hubspot
hubspot
hubspot
hubspot
So you have
four buckets
to track at minimum: app-burst (10s sliding), search-secondly (1s sliding), account-daily (24h fixed, midnight in HubSpot's TZ), and per-app daily share (your own budgeting on top of the account cap).
Where to store it
Where to store it
Redis. It's the only realistic option once you have multiple queue workers — DB-backed counters serialize too much, and in-process state can't coordinate across workers. Laravel already speaks Redis natively, and you get atomic
INCR
/
EXPIRE
plus Lua scripting for true CAS semantics.
Key layout I'd use:
Copy to clipboard
hubspot:rl:burst:{portalId}:{appId} ZSET (sliding 10s)
hubspot:rl:search:{portalId} ZSET (sliding 1s)
hubspot:rl:daily:{portalId} STRING + TTL to midnight TZ
hubspot:rl:meta:{portalId} HASH (last seen headers)
The two short-window buckets are sliding-window-log (Redis ZSET, score =
microtime
, member = unique request id). Lua script removes entries older than the window, counts remaining slots, and only adds the new one if there's room — all atomic. Fixed windows are simpler but allow 2× the limit at the boundary, which on a 5/s window is brutal.
The daily bucket is a plain
INCR
with TTL set to seconds-until-midnight in
HubSpot's account timezone
, not yours — Sofia is UTC+2/+3 but your portal might be set to US Eastern. Get this once and cache it.
How to read it
How to read it
Two-phase: optimistic pre-check, authoritative post-update.
Before a call, run the Lua acquire script. If it returns "denied," sleep until a slot frees up (the script can return ms-until-next-slot) or push the job back to the queue with a delay. Don't busy-loop.
After the call, parse
X-HubSpot-RateLimit-Remaining
/
-Max
/
-Interval-Milliseconds
and store them in
hubspot:rl:meta:{portalId}
. This is your reality check — if your local counter says 50 remaining but HubSpot's header says 5, you trust HubSpot and clamp your counter. This handles clock drift, missed accounting (e.g., crashed worker that took a token but never made the request), and other apps in the same account consuming the daily budget invisibly.
For search specifically, since headers don't come back, the local counter
is
the source of truth — meaning if you ever crash mid-flight, you've under-counted. Always release tokens on connection-level failure but
not
on 429 (you really did make that request).
How to work with multiple jobs
How to work with multiple jobs
The queue layer needs to enforce concurrency separately from the rate limiter. Both work together:
Concurrency cap
via
Queue::throttle()
or a Redis semaphore — limits how many sync workers run in parallel against HubSpot. Without this, you can have 50 workers all blocked waiting for tokens, which is wasteful and creates retry storms.
Per-tenant fairness
— if you sync many Jiminny customers into different HubSpot portals, each portal has its own bucket but you still want one slow portal not to starve others. Either separate queues per portal or a fair-share scheduler.
Priority lanes
— webhook-driven updates (user-visible latency) should outrank background batch syncs. Two queues:
hubspot-priority
and
hubspot-bulk
, with priority workers taking 70% of the burst budget and bulk taking 30% (enforce via separate sub-buckets if you really want hard separation, otherwise just pull from priority first).
Backoff on 429
— respect the
Retry-After
header. If absent, exponential with jitter (e.g.,
min(2^attempt * 250ms, 30s) ± 20%
). The jitter is non-negotiable; without it, simultaneous 429s retry in lockstep and you get thundering-herd 429s on retry.
How to work with paginated requests
How to work with paginated requests
The trap is treating "fetch all" as one logical operation. Each page is its own API call and competes for tokens with everything else.
Two practical rules:
Don't hold the worker idle while paginating.
If page N takes 500ms and page N+1 needs to wait 800ms for a token, you've burned 800ms of worker time doing nothing. Instead, fetch page N, dispatch the
processing
of page N as a separate job, and queue a "fetch page N+1" job with a delay equal to the wait time. Each page becomes its own atomic unit.
Always batch where HubSpot offers it.
POST /crm/v3/objects/{type}/batch/{read|update|create}
accepts up to 100 IDs per call. For your "patching IDs" flow this is the difference between 600 calls and 6.
Walkthrough: 600 opportunities
Walkthrough: 600 opportunities
Naive flow (one PATCH per deal): 600 calls. At 190/10s that's ~32s of API time, well under daily. You'd hit burst easily without throttling. Plus likely 1-3 search calls upfront and N association calls.
Sane flow:
Identify deltas
— if you can avoid Search at all, do. Use
lastmodifieddate
filter on a single search if you must, paginate at limit=200. For 600 deals that's 3 search calls @ 5/s = ~600ms naturally throttled.
Batch read
current state —
POST /crm/v3/objects/deals/batch/read
with 100 IDs per call → 6 calls. Burst weight 6.
Compute diff
in your code (no API).
Batch update
—
POST /crm/v3/objects/deals/batch/update
with 100 per call → 6 calls.
Associations
—
POST /crm/v4/associations/{from}/{to}/batch/create
if needed → another few batch calls.
Total: ~15-20 API calls for 600 deals. Burst budget consumed: 20/190 over ~5s. Daily impact: trivial.
Recognition: pre-check denies if
<weight>
slots aren't free; on 429 the response surfaces
policyName
(DAILY/SECONDLY) — log it, push the job back with
Retry-After
delay, increment a metric so you can alarm on sustained 429 rate.
Pitfalls & bottlenecks worth pre-empting
Pitfalls & bottlenecks worth pre-empting
Daily quota is shared across the whole portal
, including any n8n flows, other private apps, marketing automation calling APIs, etc. Budget for ~70-80% of the documented limit, not 100%. Add an internal per-app daily cap so a runaway sync can't starve other apps.
Search is uniquely fragile
: separate 5/s bucket, no headers to read, 10k-result cap per query. If you ever hit 10k+ deals matching a filter, partition by
hs_object_id
ranges or by
lastmodifieddate
windows.
Retry storms after HubSpot incidents
— always jitter, always cap total retries (e.g., 5 attempts, then dead-letter).
Webhook → sync → webhook loops
— when your update fires a HubSpot webhook that triggers another sync. Tag your own writes (e.g., a custom property
jy_last_sync_id
) and ignore webhooks where it just changed.
Token refresh
— OAuth refresh itself counts against burst. Cache the access token in Redis with TTL =
expires_in - 60s
, single-flight the refresh (only one worker refreshes; others wait on a lock).
Search latency for fresh writes
— newly created/updated objects don't appear in search instantly. Don't write-then-search; use returned IDs directly.
Clock skew
— Redis is authoritative. Don't use
time()
from each worker for window scoring; use
redis.call('TIME')
inside the Lua script.
Dead workers with held tokens
— sliding-window-log handles this naturally because tokens expire by score; token-bucket implementations need explicit release-on-crash logic.
The 5% error rule
counts every 429 toward your error budget, even successfully retried ones. If your pre-check is working well, 429s should be near zero — if they're not, your pre-check is wrong, not just slow.
Phantom contention with Laravel
RateLimited
middleware
: it's per-job-class by default, not per-portal. If your
SyncDealJob
and
UpdateActivityJob
are different classes both calling HubSpot, they don't share a Laravel-level limiter — you need a single
HubspotRateLimiter
service that everything routes through.
If you want, I can sketch the Lua script for the sliding-window acquire and the Laravel service wrapper around it.
Copy
Give positive feedback
Give negative feedback
Retry
You said: What will happen if there are two different types of rate limits?
You said: What will happen if there are two different types of rate limits?
What will happen if there are two different types of rate limits?
Search requests that have 5 requests per second
The other rate limit that has, let's say, 100 requests per 10 seconds How do these work together? Is there some conflict? Can I reach the limit with one request and block either as well, or are these separated? Can I still continue making search requests once I hit the normal requests limits?
13:40
Retry
Edit
Copy
Claude responded: They're independent buckets — with one shared bucket on top.
Claude responded: They're independent buckets — with one shared bucket on top.
Analyzed independent rate limit buckets and their practical interactions
Analyzed independent rate limit buckets and their practical interactions
They're independent buckets — with one shared bucket on top.
The three buckets and what each call hits
The three buckets and what each call hits
Copy to clipboard
┌──────────────────┐
Search request ──→ │ Search: 5/sec │ ──┐
└──────────────────┘ │
├──→ ┌─────────────────┐
┌──────────────────┐ │ │ Daily: 250k–1M │
Non-search call ──→ │ Burst: 190/10s │ ──┘ │ (per portal) │
└──────────────────┘ └─────────────────┘
A search call is only metered against the search bucket and the daily bucket. A non-search call (batch read/update, single PATCH, associations, etc.) is only metered against the burst bucket and the daily bucket. The two short-window buckets do not share counters.
What this means practically
What this means practically
Hitting search secondly limit (5/s):
Only further
/search
calls 429. Your batch reads, batch updates, single PATCHes, association calls — all keep working at full burst speed. This is actually useful: if your sync is bottlenecked on Search, you can pivot to using
lastmodifieddate
filters via batch endpoints, or use the IDs you already have to do batch reads, while Search cools off.
Hitting burst limit (190/10s):
Only non-search calls 429. You can still issue Search calls at 5/s. Useful for: continuing to identify deltas for queueing while in-flight updates drain, or refreshing a small set of records via Search even though your write pipeline is paused.
Hitting daily limit:
Everything stops. Search and non-search alike. Doesn't unblock until midnight in your portal's configured timezone — and remember this is shared across every private app in the portal, plus n8n flows, marketing tools, anything else hitting the API with that account.
So can one type of request block the other?
So can one type of request block the other?
Search → Burst:
No.
Saturating Search at 50 calls per 10s leaves your full 190/10s burst untouched.
Burst → Search:
No.
Saturating burst leaves Search's 5/s untouched.
Either → Daily:
Yes
, but only by contributing to the same daily counter. It's volume that kills you here, not the type.
In theory you can sustain ~50 search + ~190 other =
~240 calls per 10 seconds
indefinitely (until daily runs out), because the two buckets bill independently.
Implementation consequence
Implementation consequence
Your rate limiter needs to know which bucket a request hits before it acquires. Cleanest pattern:
Copy to clipboard
php
$limiter
->
acquire
(
'search'
,
$weight
=
1
)
;
// for search endpoints only
$limiter
->
acquire
(
'burst'
,
$weight
=
1
)
;
// for everything else
$limiter
->
acquire
(
'daily'
,
$weight
=
1
)
;
// every call, both kinds
In Redis: three separate keys, three separate Lua acquire scripts (or one script with a bucket parameter). A search call calls
acquire('search')
+
acquire('daily')
. A batch update calls
acquire('burst')
+
acquire('daily')
.
One subtle pitfall: when you backoff on a 429,
inspect
policyName
in the response body
to know which bucket actually fired. If you see
SECONDLY
from a search endpoint, you only need to delay search-bound jobs — burst-bound jobs in the queue can keep running. If you blanket-pause everything on any 429, you waste capacity on the bucket that's still healthy. Two queues (or two throttle keys) make this clean; one global pause is the lazy version.
The other subtlety: the burst response gives you
X-HubSpot-RateLimit-Remaining
to clamp local state against, but search doesn't return those headers. So your search counter is unverified — be slightly more conservative there (e.g., budget 4/s instead of 5) to absorb the unaccounted-for calls.
Copy
Give positive feedback
Give negative feedback
Retry
You said: Ok, so what will happen each time I make a request?
You said: Ok, so what will happen each time I make a request?
Ok, so what will happen each time I make a request? Let's say I have 100,000 requests to make that are instant. Do I need to increment each request based on the type? For example, if there is a search request, I need to increment both the search bucket and also the daily bucket. If it's a burst, then I can go to the daily and burst buckets. If I need to check if it can make a call, do I need to see both the daily and search, or burst, respectively? Isn't that too heavy for the infrastructure, adding additional load to each request?
13:44
Retry
Edit
Copy
Claude responded: Yes, your understanding is correct — every request must check and reserve from each bucket it applies to, atomically, before the call goes out.
Claude responded: Yes, your understanding is correct — every request must check and reserve from each bucket it applies to, atomically, before the call goes out.
Analyzed per-request overhead concerns and quantified Redis performance impact
Analyzed per-request overhead concerns and quantified Redis performance impact
Yes, your understanding is correct — every request must check and reserve from each bucket it applies to, atomically, before the call goes out. But the overhead is much smaller than it sounds, and importantly, it's nowhere near your bottleneck.
What "two buckets per request" actually costs
What "two buckets per request" actually costs
Each request makes
one round trip to Redis
— not two — because you fold both bucket checks into a single Lua script that runs atomically server-side:...
|
[{"role":"AXLink","text":& [{"role":"AXLink","text":"Skip to content","depth":14,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Skip to content","depth":15,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Click to collapse","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"⌘B","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drag to resize","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Open sidebar","depth":14,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Chat","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cowork","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New chat ⌘N","depth":15,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"New chat","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"⌘N","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Projects","depth":15,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Artifacts","depth":15,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Customize","depth":15,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Pinned","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"Bulgarian citizenship application process for EU residents","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Bulgarian citizenship application process for EU residents","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Dawarich location tracking project","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Dawarich location tracking project","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Recents","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"View all","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HubSpot rate limit implementation strategy","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for HubSpot rate limit implementation strategy","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Screenpipe retention policy code location","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Screenpipe retention policy code location","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Viewing retention policy in screenpipe","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Viewing retention policy in screenpipe","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Clean shot x video recording termination issue","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Clean shot x video recording termination issue","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HubSpot rate limit handling with executeRequest","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for HubSpot rate limit handling with executeRequest","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Untitled","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"💬 Screen pipe. Is there ability…","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for 💬 Screen pipe. Is there ability…","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"SMB mount access inconsistency between Finder and iTerm","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for SMB mount access inconsistency between Finder and iTerm","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"💬 What is the best switch I can…","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for 💬 What is the best switch I can…","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Permission denied on screenpipe volume","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Permission denied on screenpipe volume","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Screenpipe sync database attachment error","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Screenpipe sync database attachment error","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Last swimming outing with Dani","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Last swimming outing with Dani","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Definition of incarcerated","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Definition of incarcerated","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Chromecast remote volume buttons not working","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Chromecast remote volume buttons not working","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Salesforce API errors with Organization and FieldDefinition queries","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Salesforce API errors with Organization and FieldDefinition queries","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Daily activity summary from screenpipe data","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Daily activity summary from screenpipe data","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"MacBook unexpected restarts and kanji screen","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for MacBook unexpected restarts and kanji screen","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Security patch review and testing guidance","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Security patch review and testing guidance","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Food calorie values reference","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Food calorie values reference","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tracking location history from last week","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Tracking location history from last week","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Lukas Pro","depth":15,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Get apps and extensions","depth":15,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HubSpot rate limit implementation strategy, rename chat","depth":19,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"HubSpot rate limit implementation strategy","depth":21,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"More options for HubSpot rate limit implementation strategy","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open sidebar","depth":21,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Share chat","depth":21,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Claude finished the response","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"You said: So just a solution for rate limit implementation.","depth":20,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"You said: So just a solution for rate limit implementation.","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"So just a solution for rate limit implementation. The situation currently is that there are some daily and secondary limits for HubSpot. I would like to make sure I never reach a 429 error rate limit. The requests can come from any flow. It can be:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"updating activity (engagement, meeting, call, note)","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"searching for a company or contact","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"updating deal","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"patching IDs\nReview what the limit is at the moment in the HubSpot documentation and then think of the solution:","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"where to store it","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"how to read it","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"how to work with multiple jobs","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"how to work with paginated requests Let's consider a situation when there are 600 opportunities to sync. What would be the flow? How would the rate limit be recognized? How would it be handled? What are the potential issues? [API usage guidelines and limits - HubSpot docs](","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"https://developers.hubspot.com/docs/developer-tooling/platform/usage-guidelines","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://developers.hubspot.com/docs/developer-tooling/platform/usage-guidelines","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"). Example of such a error Client error:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"POST https://api.hubapi.com/crm/v3/objects/contact/search","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"resulted in a","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"429 Too Many Requests","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT\",\"correlationId\":\"019dffc4-4 (truncated...). Think carefully about the implementation and potential issue and bottlenecks.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Show more","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:42","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Retry","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Edit","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Claude responded: Current HubSpot limits (Apr 2026)","depth":21,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Claude responded: Current HubSpot limits (Apr 2026)","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Synthesized HubSpot rate limit architecture with Redis storage and sliding window algorithms","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Synthesized HubSpot rate limit architecture with Redis storage and sliding window algorithms","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Current HubSpot limits (Apr 2026)","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Current HubSpot limits (Apr 2026)","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"For privately distributed apps (which is what Jiminny presumably uses with HubSpot), the limits are layered: a per-app burst window of 100/10s on Free/Starter, 190/10s on Pro/Enterprise, or 250/10s with the API Limit Increase add-on","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", plus a per-account daily cap of 250k / 625k / 1M depending on tier — shared across all private apps in the account","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":". The burst window is per app; the daily quota is per portal.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"hubspot","depth":26,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"hubspot","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"hubspot","depth":26,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"hubspot","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"The Search API is special: five requests per second per account, capped at 200 records per page, with a hard 10,000-result ceiling per query","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":". That's the limit the 429 in your example is hitting (","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"secondly limit","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"on","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/crm/v3/objects/contact/search","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"). It's a separate bucket from the 190/10s, and critically, search responses do not include the","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"X-HubSpot-RateLimit-*","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"headers","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— you can't read remaining capacity off the response, you have to track it yourself.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"hubspot","depth":26,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"hubspot","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"hubspot","depth":26,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"hubspot","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Non-search endpoints return","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"X-HubSpot-RateLimit-Remaining","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"-Max","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", and","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"-Interval-Milliseconds","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":". The daily headers are not returned for OAuth-authenticated calls","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", so for those you check the account-info endpoint or maintain your own counter. There's also a soft rule: errors should stay under 5% of total daily requests","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— that's enforced for marketplace listing, but it's also a sane operational target.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"hubspot","depth":26,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"hubspot","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"hubspot","depth":26,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"hubspot","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"So you have","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"four buckets","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"to track at minimum: app-burst (10s sliding), search-secondly (1s sliding), account-daily (24h fixed, midnight in HubSpot's TZ), and per-app daily share (your own budgeting on top of the account cap).","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Where to store it","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Where to store it","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Redis. It's the only realistic option once you have multiple queue workers — DB-backed counters serialize too much, and in-process state can't coordinate across workers. Laravel already speaks Redis natively, and you get atomic","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"INCR","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"EXPIRE","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"plus Lua scripting for true CAS semantics.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Key layout I'd use:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy to clipboard","depth":27,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"hubspot:rl:burst:{portalId}:{appId} ZSET (sliding 10s)","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"hubspot:rl:search:{portalId} ZSET (sliding 1s)","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"hubspot:rl:daily:{portalId} STRING + TTL to midnight TZ","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"hubspot:rl:meta:{portalId} HASH (last seen headers)","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"The two short-window buckets are sliding-window-log (Redis ZSET, score =","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"microtime","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", member = unique request id). Lua script removes entries older than the window, counts remaining slots, and only adds the new one if there's room — all atomic. Fixed windows are simpler but allow 2× the limit at the boundary, which on a 5/s window is brutal.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"The daily bucket is a plain","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"INCR","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"with TTL set to seconds-until-midnight in","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HubSpot's account timezone","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", not yours — Sofia is UTC+2/+3 but your portal might be set to US Eastern. Get this once and cache it.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"How to read it","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"How to read it","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Two-phase: optimistic pre-check, authoritative post-update.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Before a call, run the Lua acquire script. If it returns \"denied,\" sleep until a slot frees up (the script can return ms-until-next-slot) or push the job back to the queue with a delay. Don't busy-loop.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"After the call, parse","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"X-HubSpot-RateLimit-Remaining","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"-Max","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"-Interval-Milliseconds","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"and store them in","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"hubspot:rl:meta:{portalId}","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":". This is your reality check — if your local counter says 50 remaining but HubSpot's header says 5, you trust HubSpot and clamp your counter. This handles clock drift, missed accounting (e.g., crashed worker that took a token but never made the request), and other apps in the same account consuming the daily budget invisibly.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"For search specifically, since headers don't come back, the local counter","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"is","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"the source of truth — meaning if you ever crash mid-flight, you've under-counted. Always release tokens on connection-level failure but","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"not","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"on 429 (you really did make that request).","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"How to work with multiple jobs","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"How to work with multiple jobs","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"The queue layer needs to enforce concurrency separately from the rate limiter. Both work together:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Concurrency cap","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"via","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Queue::throttle()","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"or a Redis semaphore — limits how many sync workers run in parallel against HubSpot. Without this, you can have 50 workers all blocked waiting for tokens, which is wasteful and creates retry storms.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Per-tenant fairness","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— if you sync many Jiminny customers into different HubSpot portals, each portal has its own bucket but you still want one slow portal not to starve others. Either separate queues per portal or a fair-share scheduler.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Priority lanes","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— webhook-driven updates (user-visible latency) should outrank background batch syncs. Two queues:","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"hubspot-priority","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"and","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"hubspot-bulk","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", with priority workers taking 70% of the burst budget and bulk taking 30% (enforce via separate sub-buckets if you really want hard separation, otherwise just pull from priority first).","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Backoff on 429","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— respect the","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Retry-After","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"header. If absent, exponential with jitter (e.g.,","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"min(2^attempt * 250ms, 30s) ± 20%","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"). The jitter is non-negotiable; without it, simultaneous 429s retry in lockstep and you get thundering-herd 429s on retry.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"How to work with paginated requests","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"How to work with paginated requests","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"The trap is treating \"fetch all\" as one logical operation. Each page is its own API call and competes for tokens with everything else.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Two practical rules:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Don't hold the worker idle while paginating.","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"If page N takes 500ms and page N+1 needs to wait 800ms for a token, you've burned 800ms of worker time doing nothing. Instead, fetch page N, dispatch the","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"processing","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"of page N as a separate job, and queue a \"fetch page N+1\" job with a delay equal to the wait time. Each page becomes its own atomic unit.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Always batch where HubSpot offers it.","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"POST /crm/v3/objects/{type}/batch/{read|update|create}","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"accepts up to 100 IDs per call. For your \"patching IDs\" flow this is the difference between 600 calls and 6.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Walkthrough: 600 opportunities","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Walkthrough: 600 opportunities","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Naive flow (one PATCH per deal): 600 calls. At 190/10s that's ~32s of API time, well under daily. You'd hit burst easily without throttling. Plus likely 1-3 search calls upfront and N association calls.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sane flow:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Identify deltas","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— if you can avoid Search at all, do. Use","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"lastmodifieddate","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"filter on a single search if you must, paginate at limit=200. For 600 deals that's 3 search calls @ 5/s = ~600ms naturally throttled.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Batch read","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"current state —","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"POST /crm/v3/objects/deals/batch/read","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"with 100 IDs per call → 6 calls. Burst weight 6.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Compute diff","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"in your code (no API).","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Batch update","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"—","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"POST /crm/v3/objects/deals/batch/update","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"with 100 per call → 6 calls.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Associations","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"—","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"POST /crm/v4/associations/{from}/{to}/batch/create","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"if needed → another few batch calls.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Total: ~15-20 API calls for 600 deals. Burst budget consumed: 20/190 over ~5s. Daily impact: trivial.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Recognition: pre-check denies if","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"<weight>","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"slots aren't free; on 429 the response surfaces","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"policyName","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(DAILY/SECONDLY) — log it, push the job back with","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Retry-After","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"delay, increment a metric so you can alarm on sustained 429 rate.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Pitfalls & bottlenecks worth pre-empting","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Pitfalls & bottlenecks worth pre-empting","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Daily quota is shared across the whole portal","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", including any n8n flows, other private apps, marketing automation calling APIs, etc. Budget for ~70-80% of the documented limit, not 100%. Add an internal per-app daily cap so a runaway sync can't starve other apps.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Search is uniquely fragile","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":": separate 5/s bucket, no headers to read, 10k-result cap per query. If you ever hit 10k+ deals matching a filter, partition by","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"hs_object_id","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ranges or by","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"lastmodifieddate","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"windows.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Retry storms after HubSpot incidents","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— always jitter, always cap total retries (e.g., 5 attempts, then dead-letter).","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Webhook → sync → webhook loops","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— when your update fires a HubSpot webhook that triggers another sync. Tag your own writes (e.g., a custom property","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"jy_last_sync_id","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":") and ignore webhooks where it just changed.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Token refresh","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— OAuth refresh itself counts against burst. Cache the access token in Redis with TTL =","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"expires_in - 60s","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", single-flight the refresh (only one worker refreshes; others wait on a lock).","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Search latency for fresh writes","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— newly created/updated objects don't appear in search instantly. Don't write-then-search; use returned IDs directly.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Clock skew","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— Redis is authoritative. Don't use","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"time()","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"from each worker for window scoring; use","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"redis.call('TIME')","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"inside the Lua script.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dead workers with held tokens","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— sliding-window-log handles this naturally because tokens expire by score; token-bucket implementations need explicit release-on-crash logic.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"The 5% error rule","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"counts every 429 toward your error budget, even successfully retried ones. If your pre-check is working well, 429s should be near zero — if they're not, your pre-check is wrong, not just slow.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Phantom contention with Laravel","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"RateLimited","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"middleware","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":": it's per-job-class by default, not per-portal. If your","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncDealJob","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"and","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"UpdateActivityJob","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"are different classes both calling HubSpot, they don't share a Laravel-level limiter — you need a single","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HubspotRateLimiter","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"service that everything routes through.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"If you want, I can sketch the Lua script for the sliding-window acquire and the Laravel service wrapper around it.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Give positive feedback","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Give negative feedback","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Retry","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"You said: What will happen if there are two different types of rate limits?","depth":20,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"You said: What will happen if there are two different types of rate limits?","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"What will happen if there are two different types of rate limits?","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Search requests that have 5 requests per second","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"The other rate limit that has, let's say, 100 requests per 10 seconds How do these work together? Is there some conflict? Can I reach the limit with one request and block either as well, or are these separated? Can I still continue making search requests once I hit the normal requests limits?","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"13:40","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Retry","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Edit","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Claude responded: They're independent buckets — with one shared bucket on top.","depth":21,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Claude responded: They're independent buckets — with one shared bucket on top.","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Analyzed independent rate limit buckets and their practical interactions","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Analyzed independent rate limit buckets and their practical interactions","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"They're independent buckets — with one shared bucket on top.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"The three buckets and what each call hits","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"The three buckets and what each call hits","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy to clipboard","depth":27,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"┌──────────────────┐","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Search request ──→ │ Search: 5/sec │ ──┐","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"└──────────────────┘ │","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"├──→ ┌─────────────────┐","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"┌──────────────────┐ │ │ Daily: 250k–1M │","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Non-search call ──→ │ Burst: 190/10s │ ──┘ │ (per portal) │","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"└──────────────────┘ └─────────────────┘","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"A search call is only metered against the search bucket and the daily bucket. A non-search call (batch read/update, single PATCH, associations, etc.) is only metered against the burst bucket and the daily bucket. The two short-window buckets do not share counters.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"What this means practically","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"What this means practically","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Hitting search secondly limit (5/s):","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Only further","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/search","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"calls 429. Your batch reads, batch updates, single PATCHes, association calls — all keep working at full burst speed. This is actually useful: if your sync is bottlenecked on Search, you can pivot to using","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"lastmodifieddate","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"filters via batch endpoints, or use the IDs you already have to do batch reads, while Search cools off.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Hitting burst limit (190/10s):","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Only non-search calls 429. You can still issue Search calls at 5/s. Useful for: continuing to identify deltas for queueing while in-flight updates drain, or refreshing a small set of records via Search even though your write pipeline is paused.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Hitting daily limit:","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Everything stops. Search and non-search alike. Doesn't unblock until midnight in your portal's configured timezone — and remember this is shared across every private app in the portal, plus n8n flows, marketing tools, anything else hitting the API with that account.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"So can one type of request block the other?","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"So can one type of request block the other?","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Search → Burst:","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"No.","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Saturating Search at 50 calls per 10s leaves your full 190/10s burst untouched.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Burst → Search:","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"No.","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Saturating burst leaves Search's 5/s untouched.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Either → Daily:","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Yes","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", but only by contributing to the same daily counter. It's volume that kills you here, not the type.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"In theory you can sustain ~50 search + ~190 other =","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"~240 calls per 10 seconds","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"indefinitely (until daily runs out), because the two buckets bill independently.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Implementation consequence","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Implementation consequence","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Your rate limiter needs to know which bucket a request hits before it acquires. Cleanest pattern:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy to clipboard","depth":27,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"php","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"$limiter","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"->","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"acquire","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"'search'","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"$weight","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"=","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":")","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":";","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"// for search endpoints only","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"$limiter","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"->","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"acquire","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"'burst'","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"$weight","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"=","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":")","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":";","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"// for everything else","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"$limiter","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"->","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"acquire","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"'daily'","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"$weight","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"=","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":")","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":";","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"// every call, both kinds","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"In Redis: three separate keys, three separate Lua acquire scripts (or one script with a bucket parameter). A search call calls","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"acquire('search')","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"+","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"acquire('daily')","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":". A batch update calls","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"acquire('burst')","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"+","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"acquire('daily')","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"One subtle pitfall: when you backoff on a 429,","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"inspect","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"policyName","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"in the response body","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"to know which bucket actually fired. If you see","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SECONDLY","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"from a search endpoint, you only need to delay search-bound jobs — burst-bound jobs in the queue can keep running. If you blanket-pause everything on any 429, you waste capacity on the bucket that's still healthy. Two queues (or two throttle keys) make this clean; one global pause is the lazy version.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"The other subtlety: the burst response gives you","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"X-HubSpot-RateLimit-Remaining","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"to clamp local state against, but search doesn't return those headers. So your search counter is unverified — be slightly more conservative there (e.g., budget 4/s instead of 5) to absorb the unaccounted-for calls.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Give positive feedback","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Give negative feedback","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Retry","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"You said: Ok, so what will happen each time I make a request?","depth":20,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"You said: Ok, so what will happen each time I make a request?","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Ok, so what will happen each time I make a request? Let's say I have 100,000 requests to make that are instant. Do I need to increment each request based on the type? For example, if there is a search request, I need to increment both the search bucket and also the daily bucket. If it's a burst, then I can go to the daily and burst buckets. If I need to check if it can make a call, do I need to see both the daily and search, or burst, respectively? Isn't that too heavy for the infrastructure, adding additional load to each request?","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"13:44","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Retry","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Edit","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Claude responded: Yes, your understanding is correct — every request must check and reserve from each bucket it applies to, atomically, before the call goes out.","depth":21,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Claude responded: Yes, your understanding is correct — every request must check and reserve from each bucket it applies to, atomically, before the call goes out.","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Analyzed per-request overhead concerns and quantified Redis performance impact","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Analyzed per-request overhead concerns and quantified Redis performance impact","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Yes, your understanding is correct — every request must check and reserve from each bucket it applies to, atomically, before the call goes out. But the overhead is much smaller than it sounds, and importantly, it's nowhere near your bottleneck.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"What \"two buckets per request\" actually costs","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"What \"two buckets per request\" actually costs","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Each request makes","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"one round trip to Redis","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— not two — because you fold both bucket checks into a single Lua script that runs atomically server-side:","depth":25,"on_screen":false,"role_description":"text"}]...
|
-8080824258776363129
|
-5760403554810635172
|
click
|
accessibility
|
NULL
|
Skip to content
Skip to content
Click to collapse
Skip to content
Skip to content
Click to collapse
⌘B
Drag to resize
Open sidebar
Chat
Cowork
Code
New chat ⌘N
New chat
⌘N
Projects
Artifacts
Customize
Pinned
Bulgarian citizenship application process for EU residents
More options for Bulgarian citizenship application process for EU residents
Dawarich location tracking project
More options for Dawarich location tracking project
Recents
View all
HubSpot rate limit implementation strategy
More options for HubSpot rate limit implementation strategy
Screenpipe retention policy code location
More options for Screenpipe retention policy code location
Viewing retention policy in screenpipe
More options for Viewing retention policy in screenpipe
Clean shot x video recording termination issue
More options for Clean shot x video recording termination issue
HubSpot rate limit handling with executeRequest
More options for HubSpot rate limit handling with executeRequest
Untitled
More options
💬 Screen pipe. Is there ability…
More options for 💬 Screen pipe. Is there ability…
SMB mount access inconsistency between Finder and iTerm
More options for SMB mount access inconsistency between Finder and iTerm
💬 What is the best switch I can…
More options for 💬 What is the best switch I can…
Permission denied on screenpipe volume
More options for Permission denied on screenpipe volume
Screenpipe sync database attachment error
More options for Screenpipe sync database attachment error
Last swimming outing with Dani
More options for Last swimming outing with Dani
Definition of incarcerated
More options for Definition of incarcerated
Chromecast remote volume buttons not working
More options for Chromecast remote volume buttons not working
Salesforce API errors with Organization and FieldDefinition queries
More options for Salesforce API errors with Organization and FieldDefinition queries
Daily activity summary from screenpipe data
More options for Daily activity summary from screenpipe data
MacBook unexpected restarts and kanji screen
More options for MacBook unexpected restarts and kanji screen
Security patch review and testing guidance
More options for Security patch review and testing guidance
Food calorie values reference
More options for Food calorie values reference
Tracking location history from last week
More options for Tracking location history from last week
Lukas Pro
Get apps and extensions
HubSpot rate limit implementation strategy, rename chat
HubSpot rate limit implementation strategy
More options for HubSpot rate limit implementation strategy
Open sidebar
Share chat
Claude finished the response
You said: So just a solution for rate limit implementation.
You said: So just a solution for rate limit implementation.
So just a solution for rate limit implementation. The situation currently is that there are some daily and secondary limits for HubSpot. I would like to make sure I never reach a 429 error rate limit. The requests can come from any flow. It can be:
updating activity (engagement, meeting, call, note)
searching for a company or contact
updating deal
patching IDs
Review what the limit is at the moment in the HubSpot documentation and then think of the solution:
where to store it
how to read it
how to work with multiple jobs
how to work with paginated requests Let's consider a situation when there are 600 opportunities to sync. What would be the flow? How would the rate limit be recognized? How would it be handled? What are the potential issues? [API usage guidelines and limits - HubSpot docs](
https://developers.hubspot.com/docs/developer-tooling/platform/usage-guidelines
https://developers.hubspot.com/docs/developer-tooling/platform/usage-guidelines
). Example of such a 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":"019dffc4-4 (truncated...). Think carefully about the implementation and potential issue and bottlenecks.
Show more
10:42
Retry
Edit
Copy
Claude responded: Current HubSpot limits (Apr 2026)
Claude responded: Current HubSpot limits (Apr 2026)
Synthesized HubSpot rate limit architecture with Redis storage and sliding window algorithms
Synthesized HubSpot rate limit architecture with Redis storage and sliding window algorithms
Current HubSpot limits (Apr 2026)
Current HubSpot limits (Apr 2026)
For privately distributed apps (which is what Jiminny presumably uses with HubSpot), the limits are layered: a per-app burst window of 100/10s on Free/Starter, 190/10s on Pro/Enterprise, or 250/10s with the API Limit Increase add-on
, plus a per-account daily cap of 250k / 625k / 1M depending on tier — shared across all private apps in the account
. The burst window is per app; the daily quota is per portal.
hubspot
hubspot
hubspot
hubspot
The Search API is special: five requests per second per account, capped at 200 records per page, with a hard 10,000-result ceiling per query
. That's the limit the 429 in your example is hitting (
secondly limit
on
/crm/v3/objects/contact/search
). It's a separate bucket from the 190/10s, and critically, search responses do not include the
X-HubSpot-RateLimit-*
headers
— you can't read remaining capacity off the response, you have to track it yourself.
hubspot
hubspot
hubspot
hubspot
Non-search endpoints return
X-HubSpot-RateLimit-Remaining
,
-Max
, and
-Interval-Milliseconds
. The daily headers are not returned for OAuth-authenticated calls
, so for those you check the account-info endpoint or maintain your own counter. There's also a soft rule: errors should stay under 5% of total daily requests
— that's enforced for marketplace listing, but it's also a sane operational target.
hubspot
hubspot
hubspot
hubspot
So you have
four buckets
to track at minimum: app-burst (10s sliding), search-secondly (1s sliding), account-daily (24h fixed, midnight in HubSpot's TZ), and per-app daily share (your own budgeting on top of the account cap).
Where to store it
Where to store it
Redis. It's the only realistic option once you have multiple queue workers — DB-backed counters serialize too much, and in-process state can't coordinate across workers. Laravel already speaks Redis natively, and you get atomic
INCR
/
EXPIRE
plus Lua scripting for true CAS semantics.
Key layout I'd use:
Copy to clipboard
hubspot:rl:burst:{portalId}:{appId} ZSET (sliding 10s)
hubspot:rl:search:{portalId} ZSET (sliding 1s)
hubspot:rl:daily:{portalId} STRING + TTL to midnight TZ
hubspot:rl:meta:{portalId} HASH (last seen headers)
The two short-window buckets are sliding-window-log (Redis ZSET, score =
microtime
, member = unique request id). Lua script removes entries older than the window, counts remaining slots, and only adds the new one if there's room — all atomic. Fixed windows are simpler but allow 2× the limit at the boundary, which on a 5/s window is brutal.
The daily bucket is a plain
INCR
with TTL set to seconds-until-midnight in
HubSpot's account timezone
, not yours — Sofia is UTC+2/+3 but your portal might be set to US Eastern. Get this once and cache it.
How to read it
How to read it
Two-phase: optimistic pre-check, authoritative post-update.
Before a call, run the Lua acquire script. If it returns "denied," sleep until a slot frees up (the script can return ms-until-next-slot) or push the job back to the queue with a delay. Don't busy-loop.
After the call, parse
X-HubSpot-RateLimit-Remaining
/
-Max
/
-Interval-Milliseconds
and store them in
hubspot:rl:meta:{portalId}
. This is your reality check — if your local counter says 50 remaining but HubSpot's header says 5, you trust HubSpot and clamp your counter. This handles clock drift, missed accounting (e.g., crashed worker that took a token but never made the request), and other apps in the same account consuming the daily budget invisibly.
For search specifically, since headers don't come back, the local counter
is
the source of truth — meaning if you ever crash mid-flight, you've under-counted. Always release tokens on connection-level failure but
not
on 429 (you really did make that request).
How to work with multiple jobs
How to work with multiple jobs
The queue layer needs to enforce concurrency separately from the rate limiter. Both work together:
Concurrency cap
via
Queue::throttle()
or a Redis semaphore — limits how many sync workers run in parallel against HubSpot. Without this, you can have 50 workers all blocked waiting for tokens, which is wasteful and creates retry storms.
Per-tenant fairness
— if you sync many Jiminny customers into different HubSpot portals, each portal has its own bucket but you still want one slow portal not to starve others. Either separate queues per portal or a fair-share scheduler.
Priority lanes
— webhook-driven updates (user-visible latency) should outrank background batch syncs. Two queues:
hubspot-priority
and
hubspot-bulk
, with priority workers taking 70% of the burst budget and bulk taking 30% (enforce via separate sub-buckets if you really want hard separation, otherwise just pull from priority first).
Backoff on 429
— respect the
Retry-After
header. If absent, exponential with jitter (e.g.,
min(2^attempt * 250ms, 30s) ± 20%
). The jitter is non-negotiable; without it, simultaneous 429s retry in lockstep and you get thundering-herd 429s on retry.
How to work with paginated requests
How to work with paginated requests
The trap is treating "fetch all" as one logical operation. Each page is its own API call and competes for tokens with everything else.
Two practical rules:
Don't hold the worker idle while paginating.
If page N takes 500ms and page N+1 needs to wait 800ms for a token, you've burned 800ms of worker time doing nothing. Instead, fetch page N, dispatch the
processing
of page N as a separate job, and queue a "fetch page N+1" job with a delay equal to the wait time. Each page becomes its own atomic unit.
Always batch where HubSpot offers it.
POST /crm/v3/objects/{type}/batch/{read|update|create}
accepts up to 100 IDs per call. For your "patching IDs" flow this is the difference between 600 calls and 6.
Walkthrough: 600 opportunities
Walkthrough: 600 opportunities
Naive flow (one PATCH per deal): 600 calls. At 190/10s that's ~32s of API time, well under daily. You'd hit burst easily without throttling. Plus likely 1-3 search calls upfront and N association calls.
Sane flow:
Identify deltas
— if you can avoid Search at all, do. Use
lastmodifieddate
filter on a single search if you must, paginate at limit=200. For 600 deals that's 3 search calls @ 5/s = ~600ms naturally throttled.
Batch read
current state —
POST /crm/v3/objects/deals/batch/read
with 100 IDs per call → 6 calls. Burst weight 6.
Compute diff
in your code (no API).
Batch update
—
POST /crm/v3/objects/deals/batch/update
with 100 per call → 6 calls.
Associations
—
POST /crm/v4/associations/{from}/{to}/batch/create
if needed → another few batch calls.
Total: ~15-20 API calls for 600 deals. Burst budget consumed: 20/190 over ~5s. Daily impact: trivial.
Recognition: pre-check denies if
<weight>
slots aren't free; on 429 the response surfaces
policyName
(DAILY/SECONDLY) — log it, push the job back with
Retry-After
delay, increment a metric so you can alarm on sustained 429 rate.
Pitfalls & bottlenecks worth pre-empting
Pitfalls & bottlenecks worth pre-empting
Daily quota is shared across the whole portal
, including any n8n flows, other private apps, marketing automation calling APIs, etc. Budget for ~70-80% of the documented limit, not 100%. Add an internal per-app daily cap so a runaway sync can't starve other apps.
Search is uniquely fragile
: separate 5/s bucket, no headers to read, 10k-result cap per query. If you ever hit 10k+ deals matching a filter, partition by
hs_object_id
ranges or by
lastmodifieddate
windows.
Retry storms after HubSpot incidents
— always jitter, always cap total retries (e.g., 5 attempts, then dead-letter).
Webhook → sync → webhook loops
— when your update fires a HubSpot webhook that triggers another sync. Tag your own writes (e.g., a custom property
jy_last_sync_id
) and ignore webhooks where it just changed.
Token refresh
— OAuth refresh itself counts against burst. Cache the access token in Redis with TTL =
expires_in - 60s
, single-flight the refresh (only one worker refreshes; others wait on a lock).
Search latency for fresh writes
— newly created/updated objects don't appear in search instantly. Don't write-then-search; use returned IDs directly.
Clock skew
— Redis is authoritative. Don't use
time()
from each worker for window scoring; use
redis.call('TIME')
inside the Lua script.
Dead workers with held tokens
— sliding-window-log handles this naturally because tokens expire by score; token-bucket implementations need explicit release-on-crash logic.
The 5% error rule
counts every 429 toward your error budget, even successfully retried ones. If your pre-check is working well, 429s should be near zero — if they're not, your pre-check is wrong, not just slow.
Phantom contention with Laravel
RateLimited
middleware
: it's per-job-class by default, not per-portal. If your
SyncDealJob
and
UpdateActivityJob
are different classes both calling HubSpot, they don't share a Laravel-level limiter — you need a single
HubspotRateLimiter
service that everything routes through.
If you want, I can sketch the Lua script for the sliding-window acquire and the Laravel service wrapper around it.
Copy
Give positive feedback
Give negative feedback
Retry
You said: What will happen if there are two different types of rate limits?
You said: What will happen if there are two different types of rate limits?
What will happen if there are two different types of rate limits?
Search requests that have 5 requests per second
The other rate limit that has, let's say, 100 requests per 10 seconds How do these work together? Is there some conflict? Can I reach the limit with one request and block either as well, or are these separated? Can I still continue making search requests once I hit the normal requests limits?
13:40
Retry
Edit
Copy
Claude responded: They're independent buckets — with one shared bucket on top.
Claude responded: They're independent buckets — with one shared bucket on top.
Analyzed independent rate limit buckets and their practical interactions
Analyzed independent rate limit buckets and their practical interactions
They're independent buckets — with one shared bucket on top.
The three buckets and what each call hits
The three buckets and what each call hits
Copy to clipboard
┌──────────────────┐
Search request ──→ │ Search: 5/sec │ ──┐
└──────────────────┘ │
├──→ ┌─────────────────┐
┌──────────────────┐ │ │ Daily: 250k–1M │
Non-search call ──→ │ Burst: 190/10s │ ──┘ │ (per portal) │
└──────────────────┘ └─────────────────┘
A search call is only metered against the search bucket and the daily bucket. A non-search call (batch read/update, single PATCH, associations, etc.) is only metered against the burst bucket and the daily bucket. The two short-window buckets do not share counters.
What this means practically
What this means practically
Hitting search secondly limit (5/s):
Only further
/search
calls 429. Your batch reads, batch updates, single PATCHes, association calls — all keep working at full burst speed. This is actually useful: if your sync is bottlenecked on Search, you can pivot to using
lastmodifieddate
filters via batch endpoints, or use the IDs you already have to do batch reads, while Search cools off.
Hitting burst limit (190/10s):
Only non-search calls 429. You can still issue Search calls at 5/s. Useful for: continuing to identify deltas for queueing while in-flight updates drain, or refreshing a small set of records via Search even though your write pipeline is paused.
Hitting daily limit:
Everything stops. Search and non-search alike. Doesn't unblock until midnight in your portal's configured timezone — and remember this is shared across every private app in the portal, plus n8n flows, marketing tools, anything else hitting the API with that account.
So can one type of request block the other?
So can one type of request block the other?
Search → Burst:
No.
Saturating Search at 50 calls per 10s leaves your full 190/10s burst untouched.
Burst → Search:
No.
Saturating burst leaves Search's 5/s untouched.
Either → Daily:
Yes
, but only by contributing to the same daily counter. It's volume that kills you here, not the type.
In theory you can sustain ~50 search + ~190 other =
~240 calls per 10 seconds
indefinitely (until daily runs out), because the two buckets bill independently.
Implementation consequence
Implementation consequence
Your rate limiter needs to know which bucket a request hits before it acquires. Cleanest pattern:
Copy to clipboard
php
$limiter
->
acquire
(
'search'
,
$weight
=
1
)
;
// for search endpoints only
$limiter
->
acquire
(
'burst'
,
$weight
=
1
)
;
// for everything else
$limiter
->
acquire
(
'daily'
,
$weight
=
1
)
;
// every call, both kinds
In Redis: three separate keys, three separate Lua acquire scripts (or one script with a bucket parameter). A search call calls
acquire('search')
+
acquire('daily')
. A batch update calls
acquire('burst')
+
acquire('daily')
.
One subtle pitfall: when you backoff on a 429,
inspect
policyName
in the response body
to know which bucket actually fired. If you see
SECONDLY
from a search endpoint, you only need to delay search-bound jobs — burst-bound jobs in the queue can keep running. If you blanket-pause everything on any 429, you waste capacity on the bucket that's still healthy. Two queues (or two throttle keys) make this clean; one global pause is the lazy version.
The other subtlety: the burst response gives you
X-HubSpot-RateLimit-Remaining
to clamp local state against, but search doesn't return those headers. So your search counter is unverified — be slightly more conservative there (e.g., budget 4/s instead of 5) to absorb the unaccounted-for calls.
Copy
Give positive feedback
Give negative feedback
Retry
You said: Ok, so what will happen each time I make a request?
You said: Ok, so what will happen each time I make a request?
Ok, so what will happen each time I make a request? Let's say I have 100,000 requests to make that are instant. Do I need to increment each request based on the type? For example, if there is a search request, I need to increment both the search bucket and also the daily bucket. If it's a burst, then I can go to the daily and burst buckets. If I need to check if it can make a call, do I need to see both the daily and search, or burst, respectively? Isn't that too heavy for the infrastructure, adding additional load to each request?
13:44
Retry
Edit
Copy
Claude responded: Yes, your understanding is correct — every request must check and reserve from each bucket it applies to, atomically, before the call goes out.
Claude responded: Yes, your understanding is correct — every request must check and reserve from each bucket it applies to, atomically, before the call goes out.
Analyzed per-request overhead concerns and quantified Redis performance impact
Analyzed per-request overhead concerns and quantified Redis performance impact
Yes, your understanding is correct — every request must check and reserve from each bucket it applies to, atomically, before the call goes out. But the overhead is much smaller than it sounds, and importantly, it's nowhere near your bottleneck.
What "two buckets per request" actually costs
What "two buckets per request" actually costs
Each request makes
one round trip to Redis
— not two — because you fold both bucket checks into a single Lua script that runs atomically server-side:...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
24775
|
1037
|
3
|
2026-05-12T09:54:30.458610+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-12/1778 /Users/lukas/.screenpipe/data/data/2026-05-12/1778579670458_m2.jpg...
|
Slack
|
Galya Dimitrova (DM) - Jiminny Inc - 4 new items - Galya Dimitrova (DM) - Jiminny Inc - 4 new items - Slack...
|
True
|
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
Galya Dimitrova
Steliyan Georgiev
Petko Kashinski
Aneliya Angelova
Stefka Stoyanova
Vasil Vasilev
Nikolay Ivanov
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Lukas Kovalik
you
Jira Cloud
Toast
Google Calendar
Messages
Messages
Files
Files
Untitled
Untitled
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Today at 12:08:38 PM
12:08
този Планхат да ти кажа само проблеми с него
Today at 12:08:42 PM
12:08
каквото и да се пробваш да правиш
Lukas Kovalik
Today at 12:09:04 PM
12:09 PM
да явно беше cache
Today at 12:09:48 PM
12:09
това за sentry при липсващ pdf_url се оказа само един репорт
Today at 12:10:16 PM
12:10
същия го има като podcast и си работи
Today at 12:11:12 PM
12:11
Говорих със Стели да погледне някаква валидация в самия prophet
Today at 12:11:51 PM
12:11
ще го види още и ако трябва за бъдеше да направиме някакъв flow
Today at 12:12:01 PM
12:12
image.png
Toggle file
image.png
Galya Dimitrova
Today at 12:12:26 PM
12:12 PM
ок, ако е само един репорт може сега да го сетнем него на failed или нещо друго за да спре да спами сентри
Today at 12:12:33 PM
12:12
и да оставя тикета в беклога
Today at 12:12:34 PM
12:12
как мислиш
Lukas Kovalik
Today at 12:13:20 PM
12:13 PM
добре, да му кажа да не го гледа повече на Стели?
Today at 12:13:33 PM
12:13
или все пак да има за backlog
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 12:14:16 PM
12:14
да взема ли това със UP сега?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Galya Dimitrova
Today at 12:14:26 PM
12:14 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
Lukas Kovalik
Today at 12:14:31 PM
12:14 PM
https://jiminny.atlassian.net/browse/JY-20773
https://jiminny.atlassian.net/browse/JY-20773
Jira Cloud
Jira Cloud
Remove preview
Jira Cloud Bug JY-20773 User Pilot not receiving events on report generated Bug JY-20773 in Jira Cloud Preview in Slack Status Backlog Priority Medium Medium Assignee Unassigned Unassigned As of today at 12:14 PM Refresh Open in Jira ✨ Summarise
User Pilot not receiving events on report generated
Bug JY-20773 in Jira Cloud
Preview in Slack
Status
Backlog
Priority
Medium
Assignee
Unassigned
As of today at 12:14 PM
Refresh
Open in Jira
✨ Summarise
Open in browser
Open
Share Bug JY-20773
View conversations...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.5056516,"top":0.058260176,"width":0.011968086,"height":0.028731046},"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.50299203,"top":0.10055866,"width":0.017287234,"height":0.054269753},"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.50664896,"top":0.13806863,"width":0.009973404,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.50299203,"top":0.15482841,"width":0.017287234,"height":0.054269753},"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.50764626,"top":0.19233839,"width":0.007978723,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.50299203,"top":0.20909816,"width":0.017287234,"height":0.054269753},"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.5053192,"top":0.24660814,"width":0.012965426,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5053192,"top":0.24660814,"width":0.0026595744,"height":0.011173184}},{"char_start":1,"char_count":7,"bounds":{"left":0.50764626,"top":0.24660814,"width":0.010638298,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.50299203,"top":0.26336792,"width":0.017287234,"height":0.054269753},"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.50797874,"top":0.3008779,"width":0.0076462766,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.50797874,"top":0.3008779,"width":0.0019946808,"height":0.011173184}},{"char_start":1,"char_count":4,"bounds":{"left":0.5099734,"top":0.3008779,"width":0.0056515955,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.50299203,"top":0.31763768,"width":0.017287234,"height":0.054269753},"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.50731385,"top":0.35514766,"width":0.008643617,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.50731385,"top":0.35514766,"width":0.0019946808,"height":0.011173184}},{"char_start":1,"char_count":4,"bounds":{"left":0.5093085,"top":0.35514766,"width":0.0066489363,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.50299203,"top":0.3719074,"width":0.017287234,"height":0.054269753},"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.50731385,"top":0.4094174,"width":0.008976064,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.50731385,"top":0.4094174,"width":0.0033244682,"height":0.011173184}},{"char_start":1,"char_count":3,"bounds":{"left":0.5106383,"top":0.4094174,"width":0.0056515955,"height":0.011173184}}],"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.5422208,"top":0.15562649,"width":0.043882977,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.15562649,"width":0.0013297872,"height":0.014365523}},{"char_start":1,"char_count":24,"bounds":{"left":0.54355055,"top":0.15562649,"width":0.05418883,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.5422208,"top":0.17797287,"width":0.04454787,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.17797287,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":18,"bounds":{"left":0.54521275,"top":0.17797287,"width":0.04155585,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.5422208,"top":0.23064645,"width":0.022273935,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.23064645,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":9,"bounds":{"left":0.54488033,"top":0.23064645,"width":0.019614361,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.5422208,"top":0.2529928,"width":0.012300532,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.2529928,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":5,"bounds":{"left":0.54488033,"top":0.2529928,"width":0.00930851,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.5422208,"top":0.2753392,"width":0.018284574,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.2753392,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.54521275,"top":0.2753392,"width":0.015292553,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.5422208,"top":0.29768556,"width":0.010638298,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.29768556,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":3,"bounds":{"left":0.54521275,"top":0.29768556,"width":0.00731383,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.5422208,"top":0.3200319,"width":0.034574468,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.3200319,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.54454786,"top":0.3200319,"width":0.032247342,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.5422208,"top":0.3423783,"width":0.027593086,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.3423783,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":12,"bounds":{"left":0.54454786,"top":0.3423783,"width":0.025265958,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.5422208,"top":0.36472467,"width":0.025930852,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.36472467,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":10,"bounds":{"left":0.54488033,"top":0.36472467,"width":0.022938829,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.5422208,"top":0.38707104,"width":0.016289894,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.38707104,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.54488033,"top":0.38707104,"width":0.013297873,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"bounds":{"left":0.5422208,"top":0.4094174,"width":0.023271276,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.4094174,"width":0.0013297872,"height":0.014365523}},{"char_start":1,"char_count":9,"bounds":{"left":0.54355055,"top":0.4094174,"width":0.021609042,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"bounds":{"left":0.5422208,"top":0.43176377,"width":0.034906916,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.43176377,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.54521275,"top":0.43176377,"width":0.031914894,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"bounds":{"left":0.5422208,"top":0.45411015,"width":0.03856383,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.45411015,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.54521275,"top":0.45411015,"width":0.03557181,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"bounds":{"left":0.5422208,"top":0.4764565,"width":0.016954787,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.4764565,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":5,"bounds":{"left":0.54421544,"top":0.4764565,"width":0.014960106,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"bounds":{"left":0.5422208,"top":0.49880287,"width":0.01761968,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.49880287,"width":0.0016622341,"height":0.014365523}},{"char_start":1,"char_count":7,"bounds":{"left":0.54388297,"top":0.49880287,"width":0.015957447,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"bounds":{"left":0.5422208,"top":0.5211492,"width":0.024601065,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.5211492,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":11,"bounds":{"left":0.54454786,"top":0.5211492,"width":0.021941489,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"bounds":{"left":0.5422208,"top":0.5434956,"width":0.017287234,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.5434956,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.54454786,"top":0.5434956,"width":0.01462766,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"bounds":{"left":0.5422208,"top":0.565842,"width":0.024601065,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.565842,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":9,"bounds":{"left":0.54421544,"top":0.565842,"width":0.022606382,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"bounds":{"left":0.5422208,"top":0.58818835,"width":0.045212764,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.58818835,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":20,"bounds":{"left":0.54421544,"top":0.58818835,"width":0.04720745,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"bounds":{"left":0.5422208,"top":0.6408619,"width":0.03523936,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.6408619,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":14,"bounds":{"left":0.54587764,"top":0.6408619,"width":0.03158245,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"bounds":{"left":0.5422208,"top":0.6632083,"width":0.038231384,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.6632083,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":16,"bounds":{"left":0.54488033,"top":0.6632083,"width":0.03557181,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","depth":23,"bounds":{"left":0.5422208,"top":0.6855547,"width":0.034574468,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.6855547,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":14,"bounds":{"left":0.54521275,"top":0.6855547,"width":0.03158245,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.5422208,"top":0.70790106,"width":0.03756649,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.70790106,"width":0.0033244682,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.5455452,"top":0.70790106,"width":0.034242023,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"bounds":{"left":0.5422208,"top":0.7302474,"width":0.037898935,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.7302474,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.54488033,"top":0.7302474,"width":0.03523936,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.5422208,"top":0.75259376,"width":0.026595745,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.75259376,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":12,"bounds":{"left":0.54521275,"top":0.75259376,"width":0.023271276,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"bounds":{"left":0.5422208,"top":0.77494013,"width":0.032247342,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.77494013,"width":0.0039893617,"height":0.014365523}},{"char_start":1,"char_count":13,"bounds":{"left":0.5462101,"top":0.77494013,"width":0.027925532,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.5422208,"top":0.7972865,"width":0.03756649,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.7972865,"width":0.0033244682,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.5455452,"top":0.7972865,"width":0.034242023,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"bounds":{"left":0.57978725,"top":0.7972865,"width":0.0063164895,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"bounds":{"left":0.58211434,"top":0.7972865,"width":0.014295213,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58211434,"top":0.7972865,"width":0.0039893617,"height":0.014365523}},{"char_start":1,"char_count":13,"bounds":{"left":0.58610374,"top":0.7972865,"width":0.028922873,"height":0.014365523}}],"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.5422208,"top":0.8196329,"width":0.028922873,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.8196329,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":11,"bounds":{"left":0.54488033,"top":0.8196329,"width":0.026263298,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.5422208,"top":0.84197927,"width":0.029587766,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.84197927,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":12,"bounds":{"left":0.54488033,"top":0.84197927,"width":0.026928192,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"bounds":{"left":0.5744681,"top":0.84197927,"width":0.0063164895,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5744681,"top":0.84197927,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":2,"bounds":{"left":0.5767952,"top":0.84197927,"width":0.0056515955,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.5422208,"top":0.89465284,"width":0.021941489,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.89465284,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":9,"bounds":{"left":0.54421544,"top":0.89465284,"width":0.019946808,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"bounds":{"left":0.5422208,"top":0.9169992,"width":0.011635638,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.9169992,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":4,"bounds":{"left":0.54454786,"top":0.9169992,"width":0.00930851,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Google Calendar","depth":23,"bounds":{"left":0.5422208,"top":0.9393456,"width":0.030585106,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.9393456,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":14,"bounds":{"left":0.54587764,"top":0.9393456,"width":0.032912236,"height":0.014365523}}],"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.60206115,"top":0.09177973,"width":0.030917553,"height":0.030327214},"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.61136967,"top":0.10055866,"width":0.018949468,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.61136967,"top":0.10055866,"width":0.0039893617,"height":0.012769354}},{"char_start":1,"char_count":7,"bounds":{"left":0.61535907,"top":0.10055866,"width":0.014960106,"height":0.012769354}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.63397604,"top":0.09177973,"width":0.020944148,"height":0.030327214},"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.64328456,"top":0.10055866,"width":0.008976064,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.64328456,"top":0.10055866,"width":0.0026595744,"height":0.012769354}},{"char_start":1,"char_count":4,"bounds":{"left":0.6459442,"top":0.10055866,"width":0.0063164895,"height":0.012769354}}],"role_description":"text"},{"role":"AXRadioButton","text":"Untitled","depth":17,"bounds":{"left":0.65625,"top":0.09177973,"width":0.02925532,"height":0.030327214},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Untitled","depth":19,"bounds":{"left":0.6655585,"top":0.10055866,"width":0.015957447,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.6655585,"top":0.10055866,"width":0.0033244682,"height":0.012769354}},{"char_start":1,"char_count":7,"bounds":{"left":0.66855055,"top":0.10055866,"width":0.012965426,"height":0.012769354}}],"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.68650264,"top":0.09177973,"width":0.010970744,"height":0.030327214},"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,"bounds":{"left":0.59640956,"top":0.0518755,"width":0.015957447,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"bounds":{"left":0.59640956,"top":0.0518755,"width":0.007978723,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"bounds":{"left":0.59640956,"top":0.0518755,"width":0.013962766,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.7849069,"top":0.12689546,"width":0.025265958,"height":0.022346368},"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 12:08:38 PM","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12:08","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"този Планхат да ти кажа само проблеми с него","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Today at 12:08:42 PM","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12:08","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"каквото и да се пробваш да правиш","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Today at 12:09:04 PM","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12:09 PM","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"да явно беше cache","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Today at 12:09:48 PM","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12:09","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"това за sentry при липсващ pdf_url се оказа само един репорт","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Today at 12:10: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":"12:10","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"същия го има като podcast и си работи","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Today at 12:11:12 PM","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12:11","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Говорих със Стели да погледне някаква валидация в самия prophet","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Today at 12:11:51 PM","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12:11","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ще го види още и ако трябва за бъдеше да направиме някакъв flow","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Today at 12:12:01 PM","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12:12","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"image.png","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Toggle file","depth":24,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXLink","text":"image.png","depth":26,"on_screen":false,"role_description":"Unlabelled image","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Galya Dimitrova","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Today at 12:12:26 PM","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12:12 PM","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ок, ако е само един репорт може сега да го сетнем него на failed или нещо друго за да спре да спами сентри","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Today at 12:12:33 PM","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12:12","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"и да оставя тикета в беклога","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Today at 12:12:34 PM","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12:12","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"как мислиш","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Today at 12:13:20 PM","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12:13 PM","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"добре, да му кажа да не го гледа повече на Стели?","depth":24,"bounds":{"left":0.6180186,"top":0.11572227,"width":0.11735372,"height":0.013567438},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.6180186,"top":0.114924185,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":48,"bounds":{"left":0.62101066,"top":0.114924185,"width":0.1143617,"height":0.014365523}}],"role_description":"text"},{"role":"AXLink","text":"Today at 12:13:33 PM","depth":24,"bounds":{"left":0.6050532,"top":0.14126097,"width":0.010305851,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12:13","depth":25,"bounds":{"left":0.6050532,"top":0.14126097,"width":0.010305851,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.6050532,"top":0.14126097,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":4,"bounds":{"left":0.60738033,"top":0.14126097,"width":0.00831117,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"или все пак да има за backlog","depth":24,"bounds":{"left":0.6180186,"top":0.13886672,"width":0.06781915,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":false,"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":false,"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":false,"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 12:14:16 PM","depth":24,"bounds":{"left":0.6050532,"top":0.16520351,"width":0.010305851,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12:14","depth":25,"bounds":{"left":0.6050532,"top":0.16520351,"width":0.010305851,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"да взема ли това със UP сега?","depth":24,"bounds":{"left":0.6180186,"top":0.16280925,"width":0.068484046,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":false,"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":false,"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":false,"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":"Galya Dimitrova","depth":23,"bounds":{"left":0.6180186,"top":0.18515563,"width":0.03656915,"height":0.017557861},"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.6609042,"top":0.1867518,"width":0.0026595744,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 12:14:26 PM","depth":23,"bounds":{"left":0.66356385,"top":0.18914606,"width":0.01761968,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12:14 PM","depth":24,"bounds":{"left":0.66356385,"top":0.18914606,"width":0.01761968,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"да го види за беклога. Ако нещо лесно измисли може и скоро да го направим","depth":24,"bounds":{"left":0.6180186,"top":0.20430966,"width":0.17985372,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":false,"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":false,"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":false,"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,"bounds":{"left":0.6180186,"top":0.22665602,"width":0.030917553,"height":0.017557861},"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.64893615,"top":0.22825219,"width":0.0026595744,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 12:14:31 PM","depth":23,"bounds":{"left":0.6515958,"top":0.23064645,"width":0.017287234,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12:14 PM","depth":24,"bounds":{"left":0.6515958,"top":0.23064645,"width":0.017287234,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20773","depth":24,"bounds":{"left":0.6180186,"top":0.24581006,"width":0.10106383,"height":0.014365523},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20773","depth":25,"bounds":{"left":0.6180186,"top":0.24581006,"width":0.10106383,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.6180186,"top":0.26895452,"width":0.018949468,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Jira Cloud","depth":23,"bounds":{"left":0.63829786,"top":0.26895452,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"Remove preview","depth":25,"bounds":{"left":0.61136967,"top":0.28731045,"width":0.0066489363,"height":0.016759777},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Jira Cloud Bug JY-20773 User Pilot not receiving events on report generated Bug JY-20773 in Jira Cloud Preview in Slack Status Backlog Priority Medium Medium Assignee Unassigned Unassigned As of today at 12:14 PM Refresh Open in Jira ✨ Summarise","depth":25,"bounds":{"left":0.6180186,"top":0.2857143,"width":0.15957446,"height":0.13727055},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"User Pilot not receiving events on report generated","depth":26,"bounds":{"left":0.63829786,"top":0.29928172,"width":0.11336436,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20773 in Jira Cloud","depth":27,"bounds":{"left":0.63829786,"top":0.31524342,"width":0.051861703,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"bounds":{"left":0.63829786,"top":0.31524342,"width":0.03125,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Status","depth":26,"bounds":{"left":0.63829786,"top":0.33838788,"width":0.011968086,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Backlog","depth":26,"bounds":{"left":0.63962764,"top":0.3575419,"width":0.017287234,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Priority","depth":26,"bounds":{"left":0.6662234,"top":0.33838788,"width":0.013962766,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Medium","depth":26,"bounds":{"left":0.67420214,"top":0.3575419,"width":0.017952127,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Assignee","depth":26,"bounds":{"left":0.70146275,"top":0.33838788,"width":0.016954787,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unassigned","depth":26,"bounds":{"left":0.7094415,"top":0.3575419,"width":0.025265958,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"As of today at 12:14 PM","depth":27,"bounds":{"left":0.62234044,"top":0.3982442,"width":0.046210106,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Refresh","depth":27,"bounds":{"left":0.66988033,"top":0.40143654,"width":0.01462766,"height":0.006384677},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open in Jira","depth":27,"bounds":{"left":0.7074468,"top":0.3934557,"width":0.030917553,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"✨ Summarise","depth":27,"bounds":{"left":0.7393617,"top":0.3934557,"width":0.03523936,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Open in browser","depth":26,"bounds":{"left":0.7144282,"top":0.29928172,"width":0.022606382,"height":0.025538707},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Open","depth":27,"bounds":{"left":0.7237367,"top":0.3048683,"width":0.010638298,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Share Bug JY-20773","depth":26,"bounds":{"left":0.7400266,"top":0.29928172,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View conversations","depth":26,"bounds":{"left":0.7506649,"top":0.29928172,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-8080525240667591429
|
-4090085578328733290
|
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
Galya Dimitrova
Steliyan Georgiev
Petko Kashinski
Aneliya Angelova
Stefka Stoyanova
Vasil Vasilev
Nikolay Ivanov
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Lukas Kovalik
you
Jira Cloud
Toast
Google Calendar
Messages
Messages
Files
Files
Untitled
Untitled
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Today at 12:08:38 PM
12:08
този Планхат да ти кажа само проблеми с него
Today at 12:08:42 PM
12:08
каквото и да се пробваш да правиш
Lukas Kovalik
Today at 12:09:04 PM
12:09 PM
да явно беше cache
Today at 12:09:48 PM
12:09
това за sentry при липсващ pdf_url се оказа само един репорт
Today at 12:10:16 PM
12:10
същия го има като podcast и си работи
Today at 12:11:12 PM
12:11
Говорих със Стели да погледне някаква валидация в самия prophet
Today at 12:11:51 PM
12:11
ще го види още и ако трябва за бъдеше да направиме някакъв flow
Today at 12:12:01 PM
12:12
image.png
Toggle file
image.png
Galya Dimitrova
Today at 12:12:26 PM
12:12 PM
ок, ако е само един репорт може сега да го сетнем него на failed или нещо друго за да спре да спами сентри
Today at 12:12:33 PM
12:12
и да оставя тикета в беклога
Today at 12:12:34 PM
12:12
как мислиш
Lukas Kovalik
Today at 12:13:20 PM
12:13 PM
добре, да му кажа да не го гледа повече на Стели?
Today at 12:13:33 PM
12:13
или все пак да има за backlog
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 12:14:16 PM
12:14
да взема ли това със UP сега?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Galya Dimitrova
Today at 12:14:26 PM
12:14 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
Lukas Kovalik
Today at 12:14:31 PM
12:14 PM
https://jiminny.atlassian.net/browse/JY-20773
https://jiminny.atlassian.net/browse/JY-20773
Jira Cloud
Jira Cloud
Remove preview
Jira Cloud Bug JY-20773 User Pilot not receiving events on report generated Bug JY-20773 in Jira Cloud Preview in Slack Status Backlog Priority Medium Medium Assignee Unassigned Unassigned As of today at 12:14 PM Refresh Open in Jira ✨ Summarise
User Pilot not receiving events on report generated
Bug JY-20773 in Jira Cloud
Preview in Slack
Status
Backlog
Priority
Medium
Assignee
Unassigned
As of today at 12:14 PM
Refresh
Open in Jira
✨ Summarise
Open in browser
Open
Share Bug JY-20773
View conversations
SlackcalVIewTypeError: League|FlysystenCloudWatch | us-east-2• Jy 20820 es reindex stream moc1 [JY-20725] (HubSpot) Optimise CFJY-20725 add HS rate limit handlitPipelines - jiminny/ap( Pull requests • jiminny/appWJY-207731 User Pilot not receivini( JY-20773 fix user pilot tracking ofJY-207761 Automated report - seP Platform Sorint 2 02 . Platform Te( JY-20625 | JY-20742 | MCP POC !— Data Exoloren[JY-20776] Automated report - se8 Jiminnv• Jy-20725 add HS rate limit handlillExolore08MonitorsSettingsMistonWindowHelpny.sentry.io/issues/6873095751?end=2026-05-11T20%3A24%3A00&project=82419&start=2026-05-11T19%3A41%3.Issues / le APP-1DTF@ Ask Seer &,lypeErrorEvents (total)Users (90d)•Leaquert ysystem tiesystem:nas Argumenceru Stocation must beror type string nuirgiven, caledinz nomez uminny vendor daraveraramework eongowylapp/Jobs/AutomatedReports/SendReportJob.pho in Jiminnv\Jobs\AutomatedReports|SendReportJob:handleA Ouick Fi›2.4KResolveArchivePriority oalvAll Envs vMay 11,7:41 PM-May 11, 8:24 PM V• Filter events..0% 881233os.build54% #1 SMP Fri Mar 6 16.Mav 11 8:00 PMIIMav 11.8.20 Pview all tagsEvents v in this issueView More EventsCopy as vID: 68038eUc14 hours ago | JSONJump to: HignlightsStack Tracephp php 8.3.30Linux 6.1.164-196.303.amzn2023.aarch648884620*oroductionv HighlightshondlodlevelerrorTrace: Trace IDboseyb3belbe46909/c44C9080909046v Stack Trace DisplayCopy as vTypeErrorLeaque\Flvsvstem\Filesvstem::has(): Araument #1 (Slocation) must be of tvpe string. nulll aiven.called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php ongeneridcodeCrashed in non-app: .endor/league/flysystem/src/Filesystem.php:46 in League\Flysystem\Filesystem.Chaw 1 mord fromojann/dohc/AutomatedPenortc/SondPenortJloh.nhn.80lin Jiminnv|Jobs\AutomatedReports|SendReportJobuhandle•In AppSs3Path = SautomatedReportsService->aetMediaPath(Sreport) :Verify the file exists in S.1t Storage::onsk( clnent-data-cloud")->existsSs3Path))Sloager->error(self::LOG_PREFIX• Report file not found in S3'. ["uu1d = Sthis->reportUu1d's3Path' => Ss3Path.Assignee NN Nikolay NikolovLast seen 4 hours agoin release 884020First seen 8 months agov Seer Autofix €Meet Seer, your Al assistantDebug faster with Sentry's agent,Seer. Seer connects to vour reoos.fixes, and proposes solutions. You caneven integrate with your tavoriteadent to imolement chandes in code.[ Try out Seer nowIssue Trackinge GitHubS Jirdv ActivitvMarked as Ongoingatically by Sentry6 months ado" Regressedbv Sentrv in 757712o months ageResolvedby Martin Petkovo months agcView 3 morePeonleMP IN participatingGDIAMP +4viowod!Cimilar IecnosMeraed IssuesActivityLateMoreJiminny... ~Eh External connections* Starred• jiminny-X-integrati...platform-inner-team# Channels# ai-chapter# alerts# backend# bugs# confusion-clinic# curiosity labtt engineering# general# iiminny-bg# platform-tickets# product launchesirandom# releasesi sona-otnce# support# thank-vousd the neonle of limi..^ Direct messages.©. Galva Dimitrova DDa Stelivan GeorgievPetko Kashinskie Aneliva Angelova21 Stefka StovanovaaVasil Vaciler.Nikolav Ivanov3 Aneliya Angelova, ..S. Stoyan Tanev Elukas Kovalik v.#: AppsS lira GloudToastmi Google Cale!"suppont Dally • In zn om100% Lz• Tue 12 May 12:54:30@ Describe what you are looking fore Galya DimitrovaMessagesur FilesUntitledTodayили все пак да има за backlogда взема ли това сьс UP cera?Galya Dimitrova 12:14 PMла го вили за беклога. Ако нешо лесно измисли може и скоро ла го напоавимlukas Kovalk 12:14PMhttps://iiminnv.atlassian.net/browse/JY-20773Jira CloudUser Pilot not receiving events onSª Preview in Slack( Open|Backlog= Medium9) UnassienedlAs of today at 12:14 PM RefreshOnen in Jiracalva Dimitrova m 12:14 PMза това ла пипнеш репорта ла спое ла гьоми искаш ли тикет?иначе да, нека вилим UP kкава му е драматаLukas Kovalik 12:15 PMами ше напиша комент във съществувашGalya Dimitrova 12:22 PMидеята ми е да спрем този репорт да се проова да се праща и да спами сентри. А пьк стели вече ще гледа за фикс за оъдещи такива случаиLukas Kovalik 12:26 PMда разбрах, сега ще го маркирам като failed да не го взима следващия кронGalya Dimitrova 12:26 PMlnkas Kovalik 12.24 pMако трябва да се пипне и в кода ще си направя тикетGalya Dimitrova 12:26 PMмалко ми е лудница тука между МСР і desktop апа и какво ли още не и прескачам от чат на чатLukas Kovalik 12:27 PMразоира се и аз тояоваше по-точно да го кажаще ти пиша дали се оправилоGalya Dimitrova 12:29 PMА не. Ти сигурно ок си го казал ама чета по диагоналИ другата седмица имаме презднтации пред борда в Лондон и съм до никъдеMessage Galva Dimitrova In a meeting • Google Calendar+ Аa...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
24780
|
NULL
|
0
|
2026-05-12T09:55:33.260560+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-12/1778 /Users/lukas/.screenpipe/data/data/2026-05-12/1778579733260_m1.jpg...
|
Slack
|
Galya Dimitrova (DM) - Jiminny Inc - 4 new items - Galya Dimitrova (DM) - Jiminny Inc - 4 new items - Slack...
|
True
|
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
Galya Dimitrova
Steliyan Georgiev
Petko Kashinski
Aneliya Angelova
Stefka Stoyanova
Vasil Vasilev
Nikolay Ivanov
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Lukas Kovalik
you
Jira Cloud
Toast
Google Calendar
Messages
Messages
Files
Files
Untitled
Untitled
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Today at 12:08:38 PM
12:08
този Планхат да ти кажа само проблеми с него
Today at 12:08:42 PM
12:08
каквото и да се пробваш да правиш
Lukas Kovalik
Today at 12:09:04 PM
12:09 PM
да явно беше cache
Today at 12:09:48 PM
12:09
това за sentry при липсващ pdf_url се оказа само един репорт
Today at 12:10:16 PM
12:10
същия го има като podcast и си работи
Today at 12:11:12 PM
12:11
Говорих със Стели да погледне някаква валидация в самия prophet
Today at 12:11:51 PM
12:11
ще го види още и ако трябва за бъдеше да направиме някакъв flow
Today at 12:12:01 PM
12:12
image.png
Toggle file
image.png
Galya Dimitrova
Today at 12:12:26 PM
12:12 PM
ок, ако е само един репорт може сега да го сетнем него на failed или нещо друго за да спре да спами сентри
Today at 12:12:33 PM
12:12
и да оставя тикета в беклога
Today at 12:12:34 PM
12:12
как мислиш
Lukas Kovalik
Today at 12:13:20 PM
12:13 PM
добре, да му кажа да не го гледа повече на Стели?
Today at 12:13:33 PM
12:13
или все пак да има за backlog
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 12:14:16 PM
12:14
да взема ли това със UP сега?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Galya Dimitrova
Today at 12:14:26 PM
12:14 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
Lukas Kovalik
Today at 12:14:31 PM
12:14 PM
https://jiminny.atlassian.net/browse/JY-20773
https://jiminny.atlassian.net/browse/JY-20773
Jira Cloud
Jira Cloud
Remove preview
Jira Cloud Bug JY-20773 User Pilot not receiving events on report generated Bug JY-20773 in Jira Cloud Preview in Slack Status Backlog Priority Medium Medium Assignee Unassigned Unassigned As of today at 12:14 PM Refresh Open in Jira ✨ Summarise
User Pilot not receiving events on report generated
Bug JY-20773 in Jira Cloud
Preview in Slack
Status
Backlog
Priority
Medium
Assignee
Unassigned
As of today at 12:14 PM
Refresh
Open in Jira
✨ Summarise
Open in browser
Open
Share Bug JY-20773
View conversations...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"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,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"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":"Galya Dimitrova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","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":"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":"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":"Jira Cloud","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Google Calendar","depth":23,"bounds":{"left":0.56805557,"top":0.0,"width":0.06388889,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.56805557,"top":0.0,"width":0.007638889,"height":0.02}},{"char_start":1,"char_count":14,"bounds":{"left":0.57569444,"top":0.0,"width":0.06875,"height":0.02}}],"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"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":"Files","depth":17,"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":"Untitled","depth":17,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Untitled","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"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":true,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"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":"AXLink","text":"Today at 12:08:38 PM","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12:08","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"този Планхат да ти кажа само проблеми с него","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Today at 12:08:42 PM","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12:08","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"каквото и да се пробваш да правиш","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Today at 12:09:04 PM","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12:09 PM","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"да явно беше cache","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Today at 12:09:48 PM","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12:09","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"това за sentry при липсващ pdf_url се оказа само един репорт","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Today at 12:10: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":"12:10","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"същия го има като podcast и си работи","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Today at 12:11:12 PM","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12:11","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Говорих със Стели да погледне някаква валидация в самия prophet","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Today at 12:11:51 PM","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12:11","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ще го види още и ако трябва за бъдеше да направиме някакъв flow","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Today at 12:12:01 PM","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12:12","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"image.png","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Toggle file","depth":24,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXLink","text":"image.png","depth":26,"on_screen":false,"role_description":"Unlabelled image","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Galya Dimitrova","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Today at 12:12:26 PM","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12:12 PM","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ок, ако е само един репорт може сега да го сетнем него на failed или нещо друго за да спре да спами сентри","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Today at 12:12:33 PM","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12:12","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"и да оставя тикета в беклога","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Today at 12:12:34 PM","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12:12","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"как мислиш","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Today at 12:13:20 PM","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12:13 PM","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"добре, да му кажа да не го гледа повече на Стели?","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 12:13:33 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12:13","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"или все пак да има за backlog","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":false,"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":false,"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":false,"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 12:14: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":"12:14","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"да взема ли това със UP сега?","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":false,"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":false,"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":false,"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":"Galya Dimitrova","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 12:14:26 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12:14 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":false,"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":false,"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":false,"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":false,"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 12:14: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":"12:14 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20773","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20773","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Jira Cloud","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"Remove preview","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Jira Cloud Bug JY-20773 User Pilot not receiving events on report generated Bug JY-20773 in Jira Cloud Preview in Slack Status Backlog Priority Medium Medium Assignee Unassigned Unassigned As of today at 12:14 PM Refresh Open in Jira ✨ Summarise","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"User Pilot not receiving events on report generated","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20773 in Jira Cloud","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Status","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Backlog","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Priority","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Medium","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Assignee","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unassigned","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"As of today at 12:14 PM","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Refresh","depth":27,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open in Jira","depth":27,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"✨ Summarise","depth":27,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Open in browser","depth":26,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Open","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Share Bug JY-20773","depth":26,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View conversations","depth":26,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-8080525240667591429
|
-4090085578328733290
|
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
Galya Dimitrova
Steliyan Georgiev
Petko Kashinski
Aneliya Angelova
Stefka Stoyanova
Vasil Vasilev
Nikolay Ivanov
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Lukas Kovalik
you
Jira Cloud
Toast
Google Calendar
Messages
Messages
Files
Files
Untitled
Untitled
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Today at 12:08:38 PM
12:08
този Планхат да ти кажа само проблеми с него
Today at 12:08:42 PM
12:08
каквото и да се пробваш да правиш
Lukas Kovalik
Today at 12:09:04 PM
12:09 PM
да явно беше cache
Today at 12:09:48 PM
12:09
това за sentry при липсващ pdf_url се оказа само един репорт
Today at 12:10:16 PM
12:10
същия го има като podcast и си работи
Today at 12:11:12 PM
12:11
Говорих със Стели да погледне някаква валидация в самия prophet
Today at 12:11:51 PM
12:11
ще го види още и ако трябва за бъдеше да направиме някакъв flow
Today at 12:12:01 PM
12:12
image.png
Toggle file
image.png
Galya Dimitrova
Today at 12:12:26 PM
12:12 PM
ок, ако е само един репорт може сега да го сетнем него на failed или нещо друго за да спре да спами сентри
Today at 12:12:33 PM
12:12
и да оставя тикета в беклога
Today at 12:12:34 PM
12:12
как мислиш
Lukas Kovalik
Today at 12:13:20 PM
12:13 PM
добре, да му кажа да не го гледа повече на Стели?
Today at 12:13:33 PM
12:13
или все пак да има за backlog
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 12:14:16 PM
12:14
да взема ли това със UP сега?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Galya Dimitrova
Today at 12:14:26 PM
12:14 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
Lukas Kovalik
Today at 12:14:31 PM
12:14 PM
https://jiminny.atlassian.net/browse/JY-20773
https://jiminny.atlassian.net/browse/JY-20773
Jira Cloud
Jira Cloud
Remove preview
Jira Cloud Bug JY-20773 User Pilot not receiving events on report generated Bug JY-20773 in Jira Cloud Preview in Slack Status Backlog Priority Medium Medium Assignee Unassigned Unassigned As of today at 12:14 PM Refresh Open in Jira ✨ Summarise
User Pilot not receiving events on report generated
Bug JY-20773 in Jira Cloud
Preview in Slack
Status
Backlog
Priority
Medium
Assignee
Unassigned
As of today at 12:14 PM
Refresh
Open in Jira
✨ Summarise
Open in browser
Open
Share Bug JY-20773
View conversations
iTerm2ShellEditViewSessionScriptsProfilesWindowHelp•DOCKER₴81DEV (-zsh)O $2APP (-zsh)883>0 (ihlec2-user@ip-10-30-129-190:~ec2-user@ip-10-30-129-..84• Support Daily • in 2h 5 m100% C73• Tue 12 May 12:55:32181-zshX5screenpipe"O 886-zsh+Fordocumentation,visit [URL_WITH_CREDENTIALS] ~]$ dockerexec-it $(dockerps --format "{{.ID}}" --filter "name=ecs-worker" | head -1) /bin/bash -c "cd /home/jiminny && bash"root@a3efaa2235c4:/home/jiminny# php artisantinkerPsy Shellv0.12.21(PHP8.3.30cli) by Justin HilemanNew PHPmanualis available (latest:3.0.5).Update with"doc --update-manual'> Sresult = AutomatedReportResult::find(1872);[!] Aliasing'AutomatedReportResult' to'Jiminny\Models\AutomatedReportResult' for this Tinker session.Jiminny\Models\AutomatedReportResult{#15863id:1872,uuid: b"CO-0,/a\e¢Ht°ão11",report_id:54,name: "Coaching Profiles - 6 - 12 Apr 2026 - Client Success, UK Sales",media_type: "pdf",parent_id: null,status: 2,reason: 0,payload: "["team_id":1, "request_id": "822fa41b-afd3-43a9-a248-86b0e36f3131", "report_type": "coaching_profiles", "media_types": ["pdf","podcast"], "from_date": "2026-04-06T00:00:00+(0- 00- er ), te2uro-0012723:5905050:80, Canldurdt n.m,2), Conseal-5t Se (), requene dets sta ** (, akur -netue 1, meah, TOUyuaae*:apl, imn -ons E° conterrepertsVrepon, reore-pertd:°82272 10- 202-1, 09-0160-k cot6riss, 5,'eus* compt"ted", '"'inestamp" "2026-04-13701:11:48. 648399-00-:00', 's3_url" "S3:V//jiminny.client-dataV/5F0F4810-7e77-4086-8f69-93429ae4d70b\/reports\/822fa41b-afd3-43a9-a248-86b0e36f3131.MD","report_type":"coaching_profiles", "podcast_url":"s3:\Wjiminny.client-data\/5f0f4810-7e77-4086-8f69-93429ae4d70b\/reports\/822fa41b-afd3-43a9-a248-86b0e36f3131_podcast.txt","podcast_audio_url":"s3:\//jiminny.client-data\/5f0f4810-7e77-4086-8f69-93429ae4d70bV/reports\/822fa41b-afd3-43a9-a248-86b0e36f3131_podcast.mp3","podcast_ssml_url":"s3:\//jiminny.client-data\/Sf0f4810-7e77-4086-8f69-93429ae4d70bVreports\/822fa41b-afd3-43a9-a248-86b0e36f3131-podcast.senl"t": +2026-04-13 01:00:57"requested_at:generated_at: "2026-04-13 01:11:48",sent_at: null,created_at: "2026-04-13 01:00:27",updated_at: "2026-04-13 01:11:48",› Sresult->status = 4;› Sresult->saveO);true> exitINFOGoodbye.root@aßefaa2235c4:/home/jiminny#l...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
10764
|
484
|
7
|
2026-05-08T17:53:43.376856+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778262823376_m2.jpg...
|
Code
|
Review payment logger au… — docker [SSH: nas]
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧ Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧G) - 55 pending changes
55
Run and Debug (⇧⌘D)
Remote Explorer
Extensions (⇧⌘X) - 2 require update
2
Claude Code
Containers
EXPLORER
EXPLORER
Explorer Section: docker [SSH: nas]
Explorer Section: docker [SSH: nas]
DOCKER [SSH: NAS]
adguard
ai-stack
app-db
appflowy
audiobookshelf
auth
certs
db
media
templates
.env
.env.example
docker-compose.yml
README.md
beszel
bitwarden
dawarich
dsk-uploader
flask-app
garmin-connector
gitea
health
health-tracker
homarr
hst
immich
jellyfinht
kavita
libreoffice
linkwarden
location-logger
alembic
app
mcp-server
.env
.env.example
.gitignore
.mcp.json
M
alembic.ini
docker-compose.yml
M
Dockerfile
README.md
M
requirements.txt
M
today_map.html
mariadb
meeting-detector
mindfulmama
n8n
notifier-app
Outline Section
OUTLINE
OUTLINE
Timeline Section
TIMELINE
TIMELINE
docker-compose.yml, Editor Group 1
docker-compose.yml, Editor Group 1
docker-compose.yml, Editor Group 1
services:
postgresql:
image: docker.io/library/postgres:16-alpine
container_name: Authentik-DB
hostname: authentik-db
restart: unless-stopped
security_opt:
- no-new-privileges:true
healthcheck:
test: ["CMD-SHELL", "pg_isready -d ${POSTGRES_DB:-authentik} -U ${POSTGRES_USER:-authentik}"]
interval: 5s
timeout: 5s
retries: 5
environment:
POSTGRES_PASSWORD: [PASSWORD]
POSTGRES_USER: authentik
POSTGRES_DB: authentik
volumes:
- /volume2/docker/auth/db:/var/lib/postgresql/data
networks:
- authentik_internal
redis:
image: docker.io/library/redis:alpine
container_name: Authentik-REDIS
hostname: authentik-redis
restart: unless-stopped
security_opt:
- no-new-privileges:true
healthcheck:
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
interval: 5s
timeout: 3s
retries: 5
networks:
- authentik_internal
server:
image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG}
container_name: Authentik-Server
hostname: authentik-server
restart: unless-stopped
command: server
environment:
AUTHENTIK_REDIS__HOST: authentik-redis
AUTHENTIK_POSTGRESQL__HOST: authentik-db
AUTHENTIK_POSTGRESQL__USER: authentik
AUTHENTIK_POSTGRESQL__NAME: authentik
AUTHENTIK_POSTGRESQL__PASSWORD: [PASSWORD]
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
AUTHENTIK_ERROR_REPORTING__ENABLED: "false"
AUTHENTIK_HOST: ${AUTHENTIK_HOST}
AUTHENTIK_BOOTSTRAP_EMAIL: ${AUTHENTIK_BOOTSTRAP_EMAIL}
AUTHENTIK_BOOTSTRAP_PASSWORD: [PASSWORD]
ports:
- "9100:9000"
volumes:
- /volume2/docker/auth/media:/media
- /volume2/docker/auth/templates:/templates
depends_on:
postgresql:
condition: service_healthy
redis:
condition: service_healthy
networks:
- authentik_internal
- proxy
worker:
image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG}
container_name: Authentik-Worker
hostname: authentik-worker
restart: unless-stopped
command: worker
user: root
environment:
AUTHENTIK_REDIS__HOST: authentik-redis
AUTHENTIK_POSTGRESQL__HOST: authentik-db
AUTHENTIK_POSTGRESQL__USER: authentik
AUTHENTIK_POSTGRESQL__NAME: authentik
AUTHENTIK_POSTGRESQL__PASSWORD: [PASSWORD]
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /volume2/docker/auth/media:/media
- /volume2/docker/auth/certs:/certs
- /volume2/docker/auth/templates:/templates
depends_on:
postgresql:
condition: service_healthy
redis:
condition: service_healthy
networks:
- authentik_internal
outpost:
image: ghcr.io/goauthentik/proxy:${AUTHENTIK_TAG}
container_name: Authentik-Outpost
hostname: authentik-outpost
restart: unless-stopped
environment:
AUTHENTIK_HOST: ${AUTHENTIK_HOST}
AUTHENTIK_INSECURE: "false"
AUTHENTIK_TOKEN: ${AUTHENTIK_OUTPOST_TOKEN}
ports:
- "9101:9000"
depends_on:
- server
networks:
- authentik_internal
- proxy
networks:
authentik_internal:
internal: true
proxy:
external: true
services:
postgresql:
image: docker.io/library/postgres:16-alpine
container_name: Authentik-DB
hostname: authentik-db
restart: unless-stopped
security_opt:
- no-new-privileges:true
healthcheck:
test: ["CMD-SHELL", "pg_isready -d ${POSTGRES_DB:-authentik} -U ${POSTGRES_USER:-authentik}"]
interval: 5s
timeout: 5s
retries: 5
environment:
POSTGRES_PASSWORD: [PASSWORD]
POSTGRES_USER: authentik
POSTGRES_DB: authentik
volumes:
- /volume2/docker/auth/db:/var/lib/postgresql/data
networks:
- authentik_internal
redis:
image: docker.io/library/redis:alpine
container_name: Authentik-REDIS
hostname: authentik-redis
restart: unless-stopped
security_opt:
- no-new-privileges:true
healthcheck:
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
interval: 5s
timeout: 3s
retries: 5
networks:
- authentik_internal
server:
image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG}
container_name: Authentik-Server
hostname: authentik-server
restart: unless-stopped
command: server
environment:
AUTHENTIK_REDIS__HOST: authentik-redis
AUTHENTIK_POSTGRESQL__HOST: authentik-db
AUTHENTIK_POSTGRESQL__USER: authentik
AUTHENTIK_POSTGRESQL__NAME: authentik
AUTHENTIK_POSTGRESQL__PASSWORD: [PASSWORD]
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
AUTHENTIK_ERROR_REPORTING__ENABLED: "false"
AUTHENTIK_HOST: ${AUTHENTIK_HOST}
AUTHENTIK_BOOTSTRAP_EMAIL: ${AUTHENTIK_BOOTSTRAP_EMAIL}
AUTHENTIK_BOOTSTRAP_PASSWORD: [PASSWORD]
ports:
- "9100:9000"
volumes:
- /volume2/docker/auth/media:/media
- /volume2/docker/auth/templates:/templates
depends_on:
postgresql:
condition: service_healthy
redis:
condition: service_healthy
networks:
- authentik_internal
- proxy
worker:
image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG}
container_name: Authentik-Worker
hostname: authentik-worker
restart: unless-stopped
command: worker
user: root
environment:
AUTHENTIK_REDIS__HOST: authentik-redis
AUTHENTIK_POSTGRESQL__HOST: authentik-db
AUTHENTIK_POSTGRESQL__USER: authentik
AUTHENTIK_POSTGRESQL__NAME: authentik
AUTHENTIK_POSTGRESQL__PASSWORD: [PASSWORD]
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /volume2/docker/auth/media:/media
- /volume2/docker/auth/certs:/certs
- /volume2/docker/auth/templates:/templates
depends_on:
postgresql:
condition: service_healthy
redis:
condition: service_healthy
networks:
- authentik_internal
outpost:
image: ghcr.io/goauthentik/proxy:${AUTHENTIK_TAG}
container_name: Authentik-Outpost
hostname: authentik-outpost
restart: unless-stopped
environment:
AUTHENTIK_HOST: ${AUTHENTIK_HOST}
AUTHENTIK_INSECURE: "false"
AUTHENTIK_TOKEN: ${AUTHENTIK_OUTPOST_TOKEN}
ports:
- "9101:9000"
depends_on:
- server
networks:
- authentik_internal
- proxy
networks:
authentik_internal:
internal: true
proxy:
external: true
Review payment logger au…, Editor Group 2
Problems (⇧⌘M)
PROBLEMS
Output (⇧⌘U)
OUTPUT
Debug Console (⇧⌘Y)
DEBUG CONSOLE
Terminal (⌃`)
TERMINAL
Ports
PORTS
remote SSH: nas
SSH: nas
location-logger (Git)
location-logger
location-logger (Git) - main*, Checkout Branch/Tag...
main*
location-logger (Git) - Synchronize Changes
No Problems
0
0
No Ports Forwarded
0
Notifications
Sign In
Sign In
expanded
Command Succeeded
Review payment logger authorization implementation
Session history
New session
Message actions
review payment_logger project how toes authorization work
Thinking
Thinking
Let me explore the payment_logger project structure first.
Bash
Find payment_logger project files
IN
find /volume2/docker -type f -name "*.py" -o -name "*.yml" -o -name "*.yaml" -o -name "*.env" -o -name "*.toml" -o -name "*.cfg" | grep -i payment | head -50
Copy code to clipboard
OUT
bfs: error: /volume2/docker/portnotedb/pg_commit_ts: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_dynshmem: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_notify: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_serial: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_snapshots: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_subtrans: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_twophase: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_multixact: Permission denied.
bfs: error: /volume2/docker/portnotedb/base: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_replslot: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_tblspc: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_stat: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_stat_tmp: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_xact: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_logical: Permission denied.
bfs: error: /volume2/docker/openttd/.dbus: Permission denied.
bfs: error: /volume2/docker/immich/db: Permission denied.
bfs: error: /volume2/docker/paperlessngx/db: Permission denied.
bfs: error: /volume2/docker/appflowy/postgres: Permission denied.
bfs: error: /volume2/docker/auth/db: Permission denied.
bfs: error: /volume2/docker/openttd/.XDG/dbus-1: Permission denied.
bfs: error: /volume2/docker/openttd/.config/pulse: Permission denied.
bfs: error: /volume2/docker/openttd/.cache/openbox/sessions: Permission denied.
/volume2/docker/payments-logger/.env
/volume2/docker/payments-logger/docker-compose.yml
/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml
Bash
List docker directory contents
IN
ls /volume2/docker/
Copy code to clipboard
OUT
adguard
ai-stack
app-db
appflowy
audiobookshelf
auth
beszel
bitwarden
dawarich
dsk-uploader
flask-app
garmin-connector
gitea
health
health-tracker
homarr
hst
immich
jellyfinht
kavita
libreoffice
linkwarden
location-logger
mariadb
meeting-detector
mindfulmama
n8n
notifier-app
npm
oauth
obsidian
ollama
openttd
openvpn-client
open-webui
orchestrator
outfit-app
owntracks-stack
paperlessngx
payments-logger
personal-log
personal-log-system
player
portainer
portnotedb
reminders-app
romm
second-brain
static
stirling
syncthing
tailscale
temp-logger
test-app
tmp
torrent-stack
tree
trilium
tubearchivist
twenty
uptimekuma
ytptube
Agent:
Explore payment_logger authorization code
IN
Explore the payments-logger project at /volume2/docker/payments-logger and give me a thorough understanding of how authorization works. I need to know:
1. What auth mechanism is used (JWT, sessions, API keys, OAuth, etc.)
2. Where auth is enforced (middleware, decorators, route guards, etc.)
3. What roles/permissions exist
4. How tokens are issued, validated, and refreshed
5. Any auth-related config (env vars, settings)
Please read the key source files and give me a clear summary with file paths and line numbers for the important parts.
Bash
IN
find /volume2/docker/payments-logger -type f -name "*.py" -o -name "*.json" -o -name "*.yml" -o -name "*.yaml" | grep -E "(auth|token|jwt|session|permission|role)" | head -20
Copy code to clipboard
OUT
(Bash completed with no output)
Bash
IN
ls -la /volume2/docker/payments-logger/ 2>/dev/null || echo "Directory not found"
Copy code to clipboard
OUT
total 36
drwxrwxrwx 1 Adm1n admin 162 Mar 29 18:01 .
drwxrwxrwx 1 root root 1146 Apr 26 18:49 ..
-rwxrwxrwx 1 Adm1n admin 15233 Feb 22 17:08 API.md
drwxrwxrwx 1 Adm1n admin 88 Mar 29 15:41 backend
drwxrwxrwx 1 Adm1n admin 38 Mar 29 17:07 .claude
-rwxrwxrwx 1 Adm1n admin 1502 Mar 29 18:01 docker-compose.yml
-rwxrwxrwx 1 Adm1n admin 1066 Mar 29 15:44 .env
-rwxrwxrwx 1 Adm1n admin 1078 Feb 14 17:53 .env.example
drwxrwxrwx 1 Adm1n admin 194 Mar 29 15:44 frontend
-rwxrwxrwx 1 Adm1n admin 19 Feb 14 17:54 .gitignore
-rwxrwxrwx 1 Adm1n admin 4052 Feb 14 19:06 README.md
Bash
IN
find /volume2/docker/payments-logger/backend -type f | head -30
Copy code to clipboard
OUT
/volume2/docker/payments-logger/backend/Dockerfile
/volume2/docker/payments-logger/backend/.dockerignore
/volume2/docker/payments-logger/backend/package.json
/volume2/docker/payments-logger/backend/prisma/schema.prisma
/volume2/docker/payments-logger/backend/src/parser.js
/volume2/docker/payments-logger/backend/src/index.js
/volume2/docker/payments-logger/backend/src/auth.js
/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml
/volume2/docker/payments-logger/backend/src/routes/payments.js
/volume2/docker/payments-logger/backend/prisma/migrations/20260210_init/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260210_simplify/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260222_add_card/migration.sql
Bash
IN
find /volume2/docker/payments-logger -type f \( -name "*.js" -o -name "*.json" -o -name "*.md" \) | sort
Copy code to clipboard
OUT
/volume2/docker/payments-logger/API.md
/volume2/docker/payments-logger/backend/package.json
/volume2/docker/payments-logger/backend/src/auth.js
/volume2/docker/payments-logger/backend/src/index.js
/volume2/docker/payments-logger/backend/src/parser.js
/volume2/docker/payments-logger/backend/src/routes/payments.js
/volume2/docker/payments-logger/.claude/settings.local.json
/volume2/docker/payments-logger/frontend/package.json
/volume2/docker/payments-logger/frontend/postcss.config.js
/volume2/docker/payments-logger/frontend/src/auth.js
/volume2/docker/payments-logger/frontend/tailwind.config.js
/volume2/docker/payments-logger/frontend/vite.config.js
/volume2/docker/payments-logger/README.md
Read
.env
.env
Read
auth.js
auth.js
Read
index.js
index.js
Read
package.json
package.json
Read
auth.js
auth.js
Read
API.md
API.md
Read
payments.js
payments.js
Read
.env.example
.env.example
Read
schema.prisma
schema.prisma
Bash
IN
grep -r "API_KEY\|auth\|token\|oauth\|hydra" /volume2/docker/payments-logger/backend/src --include="*.js" -n
Copy code to clipboard
OUT
/volume2/docker/payments-logger/backend/src/index.js:6:const { bearerTokenMiddleware, wellKnownRouter } = require('./auth');
/volume2/docker/payments-logger/backend/src/index.js:18:// ── OAuth Bearer token auth (skips public paths) ──────────────────────────────
/volume2/docker/payments-logger/backend/src/auth.js:2: * OAuth 2.1 / Hydra JWT authentication for Express.
/volume2/docker/payments-logger/backend/src/auth.js:6: * - wellKnownRouter — serves /.well-known/oauth-* discovery endpoints
/volume2/docker/payments-logger/backend/src/auth.js:33:function sendUnauthorized(res, detail, error = 'invalid_token') {
/volume2/docker/payments-logger/backend/src/auth.js:39: `resource_metadata="${realm}/.well-known/oauth-protected-resource"`,
/volume2/docker/payments-logger/backend/src/auth.js:40: `authorization_server="${HYDRA_PUBLIC_URL}"`,
/volume2/docker/payments-logger/backend/src/auth.js:52: * On success, attaches the decoded payload to req.tokenPayload.
/volume2/docker/payments-logger/backend/src/auth.js:54: * @param {Set<string>} publicPaths Paths to skip auth for.
/volume2/docker/payments-logger/backend/src/auth.js:58: '/.well-known/oauth-protected-resource',
/volume2/docker/payments-logger/backend/src/auth.js:59: '/.well-known/oauth-authorization-server',
/volume2/docker/payments-logger/backend/src/auth.js:66: const auth = req.headers.authorization || '';
/volume2/docker/payments-logger/backend/src/auth.js:67: if (!auth.toLowerCase().startsWith('bearer ')) {
/volume2/docker/payments-logger/backend/src/auth.js:68: return sendUnauthorized(res, 'Bearer token required', 'invalid_request');
/volume2/docker/payments-logger/backend/src/auth.js:71: const token = auth.slice(7).trim();
/volume2/docker/payments-logger/backend/src/auth.js:72: if (!token) {
/volume2/docker/payments-logger/backend/src/auth.js:73: return sendUnauthorized(res, 'Bearer token required', 'invalid_request');
/volume2/docker/payments-logger/backend/src/auth.js:82: const { payload } = await jwtVerify(token, getJwks(), verifyOptions);
/volume2/docker/payments-logger/backend/src/auth.js:83: req.tokenPayload = payload;
/volume2/docker/payments-logger/backend/src/auth.js:87: const error = msg.includes('expired') ? 'invalid_token' : 'invalid_token';
/volume2/docker/payments-logger/backend/src/auth.js:88: sendUnauthorized(res, msg, error);
/volume2/docker/payments-logger/backend/src/auth.js:98:wellKnownRouter.get('/.well-known/oauth-protected-resource', (_req, res) => {
/volume2/docker/payments-logger/backend/src/auth.js:103: authorization_servers: [HYDRA_PUBLIC_URL],
/volume2/docker/payments-logger/backend/src/auth.js:111:wellKnownRouter.get('/.well-known/oauth-authorization-server', async (_req, res) => {
/volume2/docker/payments-logger/backend/src/auth.js:119: authorization_endpoint: doc.authorization_endpoint,
/volume2/docker/payments-logger/backend/src/auth.js:120: token_endpoint: doc.token_endpoint,
/volume2/docker/payments-logger/backend/src/auth.js:123: grant_types_supported: doc.grant_types_supported || ['authorization_code', 'refresh_token'],
/volume2/docker/payments-logger/backend/src/auth.js:124: [API_KEY]: doc.[API_KEY] || ['none', 'client_secret_basic'],
/volume2/docker/payments-logger/backend/src/auth.js:128: id_token_signing_alg_values_supported: doc.id_token_signing_alg_values_supported || ['RS256'],
/volume2/docker/payments-logger/backend/src/routes/payments.js:58:// ── Ingest a payment (public — no auth) ──────────────────────────────────────
Bash
IN
find /volume2/docker/payments-logger/frontend/src -type f -name "*.js" -o -name "*.jsx" -o -name "*.ts" -o -name "*.tsx" | head -20
Copy code to clipboard
OUT
/volume2/docker/payments-logger/frontend/src/main.jsx
/volume2/docker/payments-logger/frontend/src/App.jsx
/volume2/docker/payments-logger/frontend/src/auth.js
/volume2/docker/payments-logger/frontend/src/components/PaymentCard.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentList.jsx
/volume2/docker/payments-logger/frontend/src/components/FilterBar.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentTable.jsx
/volume2/docker/payments-logger/frontend/src/components/AuthProvider.jsx
/volume2/docker/payments-logger/frontend/src/components/AuthCallback.jsx
Read
AuthProvider.jsx
AuthProvider.jsx
Read
AuthCallback.jsx
AuthCallback.jsx
Read
App.jsx
App.jsx
Read
main.jsx
main.jsx
Read
vite.config.js
vite.config.js
Bash
IN
grep -r "HYDRA\|VITE" /volume2/docker/payments-logger --include=".env*" -n
Copy code to clipboard
OUT
(Bash completed with no output)
Read
docker-compose.yml
docker-compose.yml
Bash
IN
grep -r "API_KEY" /volume2/docker/payments-logger/backend --include="*.js" -n
Copy code to clipboard
OUT
(Bash completed with no output)
Read
README.md
README.md
Bash
IN
grep -n "HYDRA\|oauth\|TOKEN" /volume2/docker/payments-logger/backend/src/index.js /volume2/docker/payments-logger/backend/src/auth.js | head -40
Copy code to clipboard
OUT
/volume2/docker/payments-logger/backend/src/auth.js:6: * - wellKnownRouter — serves /.well-known/oauth-* discovery endpoints
/volume2/docker/payments-logger/backend/src/auth.js:11:const HYDRA_PUBLIC_URL = (process.env.HYDRA_PUBLIC_URL || '').replace(/\/$/, '');
/volume2/docker/payments-logger/backend/src/auth.js:24: new URL(`${HYDRA_PUBLIC_URL}/.well-known/jwks.json`)
/volume2/docker/payments-logger/backend/src/auth.js:39: `resource_metadata="${realm}/.well-known/oauth-protected-resource"`,
/volume2/docker/payments-logger/backend/src/auth.js:40: `authorization_server="${HYDRA_PUBLIC_URL}"`,
/volume2/docker/payments-logger/backend/src/auth.js:58: '/.well-known/oauth-protected-resource',
/volume2/docker/payments-logger/backend/src/auth.js:59: '/.well-known/oauth-authorization-server',
/volume2/docker/payments-logger/backend/src/auth.js:78: issuer: HYDRA_PUBLIC_URL,
/volume2/docker/payments-logger/backend/src/auth.js:81: if (process.env.TOKEN_AUDIENCE) verifyOptions.audience = process.env.TOKEN_AUDIENCE;
/volume2/docker/payments-logger/backend/src/auth.js:98:wellKnownRouter.get('/.well-known/oauth-protected-resource', (_req, res) => {
/volume2/docker/payments-logger/backend/src/auth.js:103: authorization_servers: [HYDRA_PUBLIC_URL],
/volume2/docker/payments-logger/backend/src/auth.js:107: jwks_uri: `${HYDRA_PUBLIC_URL}/.well-known/jwks.json`,
/volume2/docker/payments-logger/backend/src/auth.js:111:wellKnownRouter.get('/.well-known/oauth-authorization-server', async (_req, res) => {
/volume2/docker/payments-logger/backend/src/auth.js:113: const r = await fetch(`${HYDRA_PUBLIC_URL}/.well-known/openid-configuration`);
/volume2/docker/payments-logger/backend/src/auth.js:118: issuer: doc.issuer || HYDRA_PUBLIC_URL,
Thinking
Thinking
payments-logger Authorization Overview
payments-logger Authorization Overview
The project uses
OAuth 2.1 with PKCE
via an external Hydra OAuth server at
hydra.lakylak.xyz
.
Auth Flow
Auth Flow
Frontend
(
frontend/src/auth.js
frontend/src/auth.js
):
Fetches OAuth server metadata via discovery endpoint
Generates a PKCE code verifier/challenge (SHA-256)
Redirects user to Hydra login with
code_challenge
On callback, exchanges code + verifier for tokens
Stores
access_token
,
refresh_token
in
localStorage
(
pl_oauth_tokens
)
Auto-refreshes token 30 seconds before expiry
Backend
(
backend/src/auth.js
backend/src/auth.js
):
bearerTokenMiddleware
validates the
Authorization: Bearer <token>
header
Fetches Hydra's JWKS (cached 300s) and verifies JWT signature (RS256/ES256/PS256)
Validates issuer (
https://hydra.lakylak.xyz
) and optional audience
Enforcement
Enforcement
Applied globally in
backend/src/index.js:19
backend/src/index.js:19
with these
public (unprotected) paths
:
/.well-known/oauth-protected-resource
/.well-known/oauth-authorization-server
/api/health
/api/payments/ingest
(rate-limited at 200 req/min — for SMS ingestion)
Roles/Permissions
Roles/Permissions
No RBAC
— it's binary: authenticated vs. unauthenticated. Required scopes:
openid
,
offline_access
.
Key Security Notes
Key Security Notes
PKCE
prevents authorization code interception
State parameter
provides CSRF protection
No server-side token storage
— validation is stateless via JWKS
The README/API docs mention an
X-API-Key
header, but that's
outdated
— the actual code uses Bearer tokens only
Config lives in
docker-compose.yml
docker-compose.yml
(lines 30–33):
HYDRA_PUBLIC_URL
,
REQUIRED_SCOPES
,
OAUTH_CLIENT_ID
, and optionally
TOKEN_AUDIENCE
/
JWKS_CACHE_TTL
.
Message actions
compare it to location logger and make it the same. Lets remove hydra and only use authentic (or whatever location logger uses).
Thinking
Thinking
Let me first explore how location-logger handles authorization.
Agent:
Explore location-logger authorization code
IN
Explore the location-logger project at /volume2/docker/location-logger and give me a thorough understanding of how authorization works. I need to know:
1. What auth mechanism is used (JWT, sessions, API keys, OAuth, etc.)
2. Where auth is enforced (middleware, decorators, route guards, etc.)
3. What roles/permissions exist
4. How tokens are issued, validated, and refreshed
5. Any auth-related config (env vars, settings)
6. Frontend auth flow (how the user logs in, how tokens are stored and used)
7. The full directory/file structure of the project
Please read ALL relevant source files completely and give me a detailed summary with file paths and line numbers. I need enough detail to replicate this auth system in another project.
Bash
IN
find /volume2/docker/location-logger -type f -name "*.py" -o -name "*.js" -o -name "*.ts" -o -name "*.json" | head -50
Copy code to clipboard
OUT
/volume2/docker/location-logger/.mcp.json
/volume2/docker/location-logger/app/__init__.py
/volume2/docker/location-logger/app/utils.py
/volume2/docker/location-logger/app/config.py
/volume2/docker/location-logger/app/main.py
/volume2/docker/location-logger/alembic/env.py
/volume2/docker/location-logger/mcp-server/server.py
/volume2/docker/location-logger/alembic/versions/20260203_201500_create_location_points_table.py
/volume2/docker/location-logger/alembic/versions/20260209_200000_add_enhanced_fields_and_tables.py
/volume2/docker/location-logger/alembic/versions/20260214_000000_add_users_and_audit_logs.py
/volume2/docker/location-logger/alembic/versions/20260320_000000_add_audit_query_string.py
/volume2/docker/location-logger/app/services/geofence_service.py
/volume2/docker/location-logger/app/services/recorder_service.py
/volume2/docker/location-logger/app/services/trip_service.py
/volume2/docker/location-logger/app/services/enhanced_location_service.py
/volume2/docker/location-logger/app/services/geocoding_service.py
/volume2/docker/location-logger/app/clients/__init__.py
/volume2/docker/location-logger/app/clients/dawarich_client.py
/volume2/docker/location-logger/app/clients/owntracks_client.py
/volume2/docker/location-logger/app/models/areas.py
/volume2/docker/location-logger/app/models/geofence_events.py
/volume2/docker/location-logger/app/models/trips.py
/volume2/docker/location-logger/app/models/user.py
/volume2/docker/location-logger/app/models/location.py
/volume2/docker/location-logger/app/models/audit_log.py
/volume2/docker/location-logger/app/auth/__init__.py
/volume2/docker/location-logger/app/auth/dependencies.py
/volume2/docker/location-logger/app/auth/utils.py
/volume2/docker/location-logger/app/api/enhanced_endpoints.py
/volume2/docker/location-logger/app/db/base.py
/volume2/docker/location-logger/app/db/session.py
Bash
IN
tree -L 4 /volume2/docker/location-logger 2>/dev/null || find /volume2/docker/location-logger -type d | sort
Copy code to clipboard
OUT
/volume2/docker/location-logger
├── alembic
│ ├── env.py
│ ├── script.py.mako
│ └── versions
│ ├── 20260203_201500_create_location_points_table.py
│ ├── 20260209_200000_add_enhanced_fields_and_tables.py
│ ├── 20260214_000000_add_users_and_audit_logs.py
│ ├── 20260320_000000_add_audit_query_string.py
│ └── __pycache__
│ └── 20260214_000000_add_users_and_audit_logs.cpython-311.pyc
├── alembic.ini
├── app
│ ├── api
│ │ └── enhanced_endpoints.py
│ ├── auth
│ │ ├── dependencies.py
│ │ ├── __init__.py
│ │ ├── __pycache__
│ │ │ ├── dependencies.cpython-311.pyc
│ │ │ ├── __init__.cpython-311.pyc
│ │ │ └── utils.cpython-311.pyc
│ │ └── utils.py
│ ├── clients
│ │ ├── dawarich_client.py
│ │ ├── __init__.py
│ │ └── owntracks_client.py
│ ├── config.py
│ ├── db
│ │ ├── base.py
│ │ └── session.py
│ ├── __init__.py
│ ├── main.py
│ ├── models
│ │ ├── areas.py
│ │ ├── audit_log.py
│ │ ├── geofence_events.py
│ │ ├── location.py
│ │ ├── __pycache__
│ │ │ ├── audit_log.cpython-311.pyc
│ │ │ └── user.cpython-311.pyc
│ │ ├── trips.py
│ │ └── user.py
│ ├── __pycache__
│ │ ├── __init__.cpython-311.pyc
│ │ └── main.cpython-311.pyc
│ ├── services
│ │ ├── enhanced_location_service.py
│ │ ├── geocoding_service.py
│ │ ├── geofence_service.py
│ │ ├── recorder_service.py
│ │ └── trip_service.py
│ ├── static
│ │ └── dashboard.html
│ └── utils.py
├── docker-compose.yml
├── Dockerfile
├── mcp-server
│ ├── Dockerfile
│ ├── requirements.txt
│ └── server.py
├── README.md
├── requirements.txt
└── today_map.html
16 directories, 48 files
Read
utils.py
utils.py
Read
dependencies.py
dependencies.py
Read
user.py
user.py
Read
config.py
config.py
Read
main.py
main.py
Read
session.py
session.py
Read
dashboard.html
dashboard.html
Read
audit_log.py
audit_log.py
Read
20260214_000000_add_users_and_audit_logs.py
20260214_000000_add_users_and_audit_logs.py
Read
20260320_000000_add_audit_query_string.py
20260320_000000_add_audit_query_string.py
Read
README.md
README.md
Read
requirements.txt
requirements.txt
Read
server.py
server.py
Read
server.py
server.py
(lines 101-400)
Thinking
Thinking
Now I have a full picture of both systems. Let me read the payments-logger source files before planning the migration.
Bash
List all payments-logger files
IN
find /volume2/docker/payments-logger -type f | grep -v node_modules | grep -v .git | sort
Copy code to clipboard
OUT
/volume2/docker/payments-logger/API.md
/volume2/docker/payments-logger/backend/Dockerfile
/volume2/docker/payments-logger/backend/.dockerignore
/volume2/docker/payments-logger/backend/package.json
/volume2/docker/payments-logger/backend/prisma/migrations/20260210_init/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260210_simplify/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260222_add_card/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml
/volume2/docker/payments-logger/backend/prisma/schema.prisma
/volume2/docker/payments-logger/backend/src/auth.js
/volume2/docker/payments-logger/backend/src/index.js
/volume2/docker/payments-logger/backend/src/parser.js
/volume2/docker/payments-logger/backend/src/routes/payments.js
/volume2/docker/payments-logger/.claude/settings.local.json
/volume2/docker/payments-logger/docker-compose.yml
/volume2/docker/payments-logger/.env
/volume2/docker/payments-logger/.env.example
/volume2/docker/payments-logger/frontend/Dockerfile
/volume2/docker/payments-logger/frontend/.dockerignore
/volume2/docker/payments-logger/frontend/index.html
/volume2/docker/payments-logger/frontend/package.json
/volume2/docker/payments-logger/frontend/postcss.config.js
/volume2/docker/payments-logger/frontend/src/App.jsx
/volume2/docker/payments-logger/frontend/src/auth.js
/volume2/docker/payments-logger/frontend/src/components/AuthCallback.jsx
/volume2/docker/payments-logger/frontend/src/components/AuthProvider.jsx
/volume2/docker/payments-logger/frontend/src/components/FilterBar.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentCard.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentList.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentTable.jsx
/volume2/docker/payments-logger/frontend/src/index.css
/volume2/docker/payments-logger/frontend/src/main.jsx
/volume2/docker/payments-logger/frontend/tailwind.config.js
/volume2/docker/payments-logger/frontend/vite.config.js
/volume2/docker/payments-logger/README.md
Read
auth.js
auth.js
Read
index.js
index.js
Read
auth.js
auth.js
Read
AuthProvider.jsx
AuthProvider.jsx
Read
package.json
package.json
Read
AuthCallback.jsx
AuthCallback.jsx
Read
schema.prisma
schema.prisma
Read
docker-compose.yml
docker-compose.yml
Thinking
Thinking
Now let me read the remaining frontend files.
Read
App.jsx
App.jsx
Read
package.json
package.json
Read
.env
.env
Thinking
Thinking
Let me read the remaining files before making changes.
Read
main.jsx
main.jsx
Read
vite.config.js
vite.config.js
Read
payments.js
payments.js
Thinking...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Explorer (⇧⌘E)","depth":19,"bounds":{"left":0.0,"top":0.047885075,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":true},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.057462092,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Search (⇧⌘F)","depth":19,"bounds":{"left":0.0,"top":0.08619314,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.09577015,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Source Control (⌃⇧G) - 55 pending changes","depth":19,"bounds":{"left":0.0,"top":0.1245012,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.13407822,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"55","depth":22,"bounds":{"left":0.0076462766,"top":0.1452514,"width":0.0043218085,"height":0.008778931},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Run and Debug (⇧⌘D)","depth":19,"bounds":{"left":0.0,"top":0.16280925,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.17238627,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Remote Explorer","depth":19,"bounds":{"left":0.0,"top":0.20111732,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.21069433,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Extensions (⇧⌘X) - 2 require update","depth":19,"bounds":{"left":0.0,"top":0.23942538,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.2490024,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":22,"bounds":{"left":0.009640957,"top":0.2601756,"width":0.0019946808,"height":0.008778931},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Claude Code","depth":19,"bounds":{"left":0.0,"top":0.27773345,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Containers","depth":19,"bounds":{"left":0.0,"top":0.3160415,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"EXPLORER","depth":17,"bounds":{"left":0.022606382,"top":0.047885075,"width":0.018949468,"height":0.02793296},"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"EXPLORER","depth":18,"bounds":{"left":0.022606382,"top":0.056664005,"width":0.018949468,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.022606382,"top":0.056664005,"width":0.0023271276,"height":0.0103751}},{"char_start":1,"char_count":7,"bounds":{"left":0.024933511,"top":0.056664005,"width":0.01662234,"height":0.0103751}}],"role_description":"text"},{"role":"AXButton","text":"Explorer Section: docker [SSH: nas]","depth":21,"bounds":{"left":0.015957447,"top":0.07581804,"width":0.09940159,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.01662234,"top":0.07821229,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"Explorer Section: docker [SSH: nas]","depth":22,"bounds":{"left":0.022606382,"top":0.07581804,"width":0.038231384,"height":0.017557861},"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"DOCKER [SSH: NAS]","depth":23,"bounds":{"left":0.022606382,"top":0.079010375,"width":0.038231384,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.022606382,"top":0.07980846,"width":0.0029920214,"height":0.0103751}},{"char_start":1,"char_count":16,"bounds":{"left":0.025598405,"top":0.07980846,"width":0.03523936,"height":0.0103751}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.09577015,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"adguard","depth":27,"bounds":{"left":0.025930852,"top":0.09577015,"width":0.01662234,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.096568234,"width":0.0023271276,"height":0.011971269}},{"char_start":1,"char_count":6,"bounds":{"left":0.02825798,"top":0.096568234,"width":0.014295213,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.11332801,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-stack","depth":27,"bounds":{"left":0.025930852,"top":0.11332801,"width":0.016289894,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.11412609,"width":0.0023271276,"height":0.011971269}},{"char_start":1,"char_count":7,"bounds":{"left":0.02825798,"top":0.11412609,"width":0.013962766,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.13088587,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"app-db","depth":27,"bounds":{"left":0.025930852,"top":0.13088587,"width":0.014960106,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.13168396,"width":0.0023271276,"height":0.011971269}},{"char_start":1,"char_count":5,"bounds":{"left":0.02825798,"top":0.13168396,"width":0.012632979,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.14844373,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"appflowy","depth":27,"bounds":{"left":0.025930852,"top":0.14844373,"width":0.018284574,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.14924182,"width":0.0023271276,"height":0.011971269}},{"char_start":1,"char_count":7,"bounds":{"left":0.02825798,"top":0.14924182,"width":0.015957447,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.1660016,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"audiobookshelf","depth":27,"bounds":{"left":0.025930852,"top":0.1660016,"width":0.030917553,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.16679968,"width":0.0023271276,"height":0.011971269}},{"char_start":1,"char_count":13,"bounds":{"left":0.02825798,"top":0.16679968,"width":0.028590426,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.18355946,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"auth","depth":27,"bounds":{"left":0.025930852,"top":0.18355946,"width":0.008976064,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.18435754,"width":0.0023271276,"height":0.011971269}},{"char_start":1,"char_count":3,"bounds":{"left":0.02825798,"top":0.18435754,"width":0.0066489363,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.022273935,"top":0.20111732,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"certs","depth":27,"bounds":{"left":0.028590426,"top":0.20111732,"width":0.010305851,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.2019154,"width":0.0023271276,"height":0.011971269}},{"char_start":1,"char_count":4,"bounds":{"left":0.030917553,"top":0.2019154,"width":0.007978723,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.022273935,"top":0.21867518,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"db","depth":27,"bounds":{"left":0.028590426,"top":0.21867518,"width":0.005319149,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.21947326,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":1,"bounds":{"left":0.03125,"top":0.21947326,"width":0.0026595744,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.022273935,"top":0.23623304,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"media","depth":27,"bounds":{"left":0.028590426,"top":0.23623304,"width":0.012300532,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.23703113,"width":0.003656915,"height":0.011971269}},{"char_start":1,"char_count":4,"bounds":{"left":0.032247342,"top":0.23703113,"width":0.008643617,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.022273935,"top":0.25379092,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"templates","depth":27,"bounds":{"left":0.028590426,"top":0.25379092,"width":0.019946808,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.254589,"width":0.0016622341,"height":0.011971269}},{"char_start":1,"char_count":8,"bounds":{"left":0.03025266,"top":0.254589,"width":0.018284574,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.2697526,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".env","depth":27,"bounds":{"left":0.028590426,"top":0.27134877,"width":0.00831117,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.27214685,"width":0.0013297872,"height":0.011971269}},{"char_start":1,"char_count":3,"bounds":{"left":0.029920213,"top":0.27214685,"width":0.006981383,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.28731045,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".env.example","depth":27,"bounds":{"left":0.028590426,"top":0.28890663,"width":0.025930852,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.2897047,"width":0.0013297872,"height":0.011971269}},{"char_start":1,"char_count":11,"bounds":{"left":0.029920213,"top":0.2897047,"width":0.024933511,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.3048683,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"docker-compose.yml","depth":27,"bounds":{"left":0.028590426,"top":0.3064645,"width":0.042220745,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.30726257,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":17,"bounds":{"left":0.03125,"top":0.30726257,"width":0.03956117,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.32242617,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"README.md","depth":27,"bounds":{"left":0.028590426,"top":0.32402235,"width":0.025265958,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.3415802,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"beszel","depth":27,"bounds":{"left":0.025930852,"top":0.3415802,"width":0.012965426,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.3423783,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":5,"bounds":{"left":0.028590426,"top":0.3423783,"width":0.010638298,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.35913807,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bitwarden","depth":27,"bounds":{"left":0.025930852,"top":0.35913807,"width":0.019946808,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.35993615,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":8,"bounds":{"left":0.028590426,"top":0.35993615,"width":0.017287234,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.37669593,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"dawarich","depth":27,"bounds":{"left":0.025930852,"top":0.37669593,"width":0.017952127,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.377494,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":7,"bounds":{"left":0.028590426,"top":0.377494,"width":0.015625,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.3942538,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"dsk-uploader","depth":27,"bounds":{"left":0.025930852,"top":0.3942538,"width":0.026928192,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.39505187,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":11,"bounds":{"left":0.028590426,"top":0.39505187,"width":0.024268618,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.10605053,"top":0.39505187,"width":0.004654255,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.41181165,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"flask-app","depth":27,"bounds":{"left":0.025930852,"top":0.41181165,"width":0.018949468,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.41260973,"width":0.0016622341,"height":0.011971269}},{"char_start":1,"char_count":8,"bounds":{"left":0.027593086,"top":0.41260973,"width":0.017287234,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.10605053,"top":0.41260973,"width":0.004654255,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.4293695,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"garmin-connector","depth":27,"bounds":{"left":0.025930852,"top":0.4293695,"width":0.036236703,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.4301676,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":15,"bounds":{"left":0.028590426,"top":0.4301676,"width":0.033909574,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.44692737,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"gitea","depth":27,"bounds":{"left":0.025930852,"top":0.44692737,"width":0.009973404,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.44772545,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":4,"bounds":{"left":0.028590426,"top":0.44772545,"width":0.00731383,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.46448523,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"health","depth":27,"bounds":{"left":0.025930852,"top":0.46448523,"width":0.012300532,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.46528333,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":5,"bounds":{"left":0.028590426,"top":0.46528333,"width":0.009973404,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.4820431,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"health-tracker","depth":27,"bounds":{"left":0.025930852,"top":0.4820431,"width":0.028590426,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.4828412,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":13,"bounds":{"left":0.028590426,"top":0.4828412,"width":0.025930852,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.49960095,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"homarr","depth":27,"bounds":{"left":0.025930852,"top":0.49960095,"width":0.014295213,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.50039905,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":5,"bounds":{"left":0.028590426,"top":0.50039905,"width":0.011968086,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.5171588,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"hst","depth":27,"bounds":{"left":0.025930852,"top":0.5171588,"width":0.0063164895,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.5179569,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":2,"bounds":{"left":0.028590426,"top":0.5179569,"width":0.003656915,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.53471667,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"immich","depth":27,"bounds":{"left":0.025930852,"top":0.53471667,"width":0.01462766,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.5355148,"width":0.0009973404,"height":0.011971269}},{"char_start":1,"char_count":5,"bounds":{"left":0.026928192,"top":0.5355148,"width":0.013630319,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.5522745,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jellyfinht","depth":27,"bounds":{"left":0.025930852,"top":0.5522745,"width":0.016954787,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.55307263,"width":0.0009973404,"height":0.011971269}},{"char_start":1,"char_count":9,"bounds":{"left":0.026928192,"top":0.55307263,"width":0.016289894,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.5698324,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"kavita","depth":27,"bounds":{"left":0.025930852,"top":0.5698324,"width":0.011635638,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.5706305,"width":0.0023271276,"height":0.011971269}},{"char_start":1,"char_count":5,"bounds":{"left":0.02825798,"top":0.5706305,"width":0.009640957,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.58739024,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"libreoffice","depth":27,"bounds":{"left":0.025930852,"top":0.58739024,"width":0.020279255,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.58818835,"width":0.0009973404,"height":0.011971269}},{"char_start":1,"char_count":10,"bounds":{"left":0.026928192,"top":0.58818835,"width":0.019281914,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.6049481,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"linkwarden","depth":27,"bounds":{"left":0.025930852,"top":0.6049481,"width":0.021609042,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.6057462,"width":0.0009973404,"height":0.011971269}},{"char_start":1,"char_count":9,"bounds":{"left":0.026928192,"top":0.6057462,"width":0.020611702,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.62250596,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"location-logger","depth":27,"bounds":{"left":0.025930852,"top":0.62250596,"width":0.030917553,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.62330407,"width":0.0009973404,"height":0.011971269}},{"char_start":1,"char_count":14,"bounds":{"left":0.026928192,"top":0.62330407,"width":0.029920213,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.10605053,"top":0.62330407,"width":0.004654255,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.022273935,"top":0.6400638,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alembic","depth":27,"bounds":{"left":0.028590426,"top":0.6400638,"width":0.015625,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.6408619,"width":0.0023271276,"height":0.011971269}},{"char_start":1,"char_count":6,"bounds":{"left":0.030917553,"top":0.6408619,"width":0.013297873,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.10605053,"top":0.6408619,"width":0.004654255,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.022273935,"top":0.6576217,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"app","depth":27,"bounds":{"left":0.028590426,"top":0.6576217,"width":0.0076462766,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.6584198,"width":0.0023271276,"height":0.011971269}},{"char_start":1,"char_count":2,"bounds":{"left":0.030917553,"top":0.6584198,"width":0.005319149,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.10605053,"top":0.6584198,"width":0.004654255,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.022273935,"top":0.67517954,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"mcp-server","depth":27,"bounds":{"left":0.028590426,"top":0.67517954,"width":0.023271276,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.67597765,"width":0.003656915,"height":0.011971269}},{"char_start":1,"char_count":9,"bounds":{"left":0.032247342,"top":0.67597765,"width":0.019946808,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.69114125,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".env","depth":27,"bounds":{"left":0.028590426,"top":0.6927374,"width":0.00831117,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.6935355,"width":0.0013297872,"height":0.011971269}},{"char_start":1,"char_count":3,"bounds":{"left":0.029920213,"top":0.6935355,"width":0.006981383,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.7086991,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".env.example","depth":27,"bounds":{"left":0.028590426,"top":0.7102953,"width":0.025930852,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.71109337,"width":0.0013297872,"height":0.011971269}},{"char_start":1,"char_count":11,"bounds":{"left":0.029920213,"top":0.71109337,"width":0.024933511,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.72625697,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".gitignore","depth":27,"bounds":{"left":0.028590426,"top":0.7278532,"width":0.018949468,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.7286512,"width":0.0013297872,"height":0.011971269}},{"char_start":1,"char_count":9,"bounds":{"left":0.029920213,"top":0.7286512,"width":0.017952127,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.7438148,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".mcp.json","depth":27,"bounds":{"left":0.028590426,"top":0.74541104,"width":0.019614361,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.7462091,"width":0.0013297872,"height":0.011971269}},{"char_start":1,"char_count":8,"bounds":{"left":0.029920213,"top":0.7462091,"width":0.018284574,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"M","depth":27,"bounds":{"left":0.10638298,"top":0.7462091,"width":0.003656915,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.7613727,"width":0.0076462766,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alembic.ini","depth":27,"bounds":{"left":0.028590426,"top":0.7629689,"width":0.021609042,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.76376694,"width":0.0023271276,"height":0.011971269}},{"char_start":1,"char_count":10,"bounds":{"left":0.030917553,"top":0.76376694,"width":0.019281914,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.77893054,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"docker-compose.yml","depth":27,"bounds":{"left":0.028590426,"top":0.78052676,"width":0.042220745,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.7813248,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":17,"bounds":{"left":0.03125,"top":0.7813248,"width":0.03956117,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"M","depth":27,"bounds":{"left":0.10638298,"top":0.7813248,"width":0.003656915,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.7964884,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Dockerfile","depth":27,"bounds":{"left":0.028590426,"top":0.7980846,"width":0.020611702,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.79888266,"width":0.0033244682,"height":0.011971269}},{"char_start":1,"char_count":9,"bounds":{"left":0.031914894,"top":0.79888266,"width":0.017287234,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.81404626,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"README.md","depth":27,"bounds":{"left":0.028590426,"top":0.8156425,"width":0.025265958,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"M","depth":27,"bounds":{"left":0.10638298,"top":0.8164405,"width":0.003656915,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.8316041,"width":0.0076462766,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"requirements.txt","depth":27,"bounds":{"left":0.028590426,"top":0.83320034,"width":0.032912236,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.8339984,"width":0.0016622341,"height":0.011971269}},{"char_start":1,"char_count":15,"bounds":{"left":0.03025266,"top":0.8339984,"width":0.03158245,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"M","depth":27,"bounds":{"left":0.10638298,"top":0.8339984,"width":0.003656915,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.849162,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"today_map.html","depth":27,"bounds":{"left":0.028590426,"top":0.8507582,"width":0.032247342,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.85155624,"width":0.0016622341,"height":0.011971269}},{"char_start":1,"char_count":13,"bounds":{"left":0.03025266,"top":0.85155624,"width":0.030585106,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.86831605,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"mariadb","depth":27,"bounds":{"left":0.025930852,"top":0.86831605,"width":0.016289894,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.8691141,"width":0.003656915,"height":0.011971269}},{"char_start":1,"char_count":6,"bounds":{"left":0.029587766,"top":0.8691141,"width":0.012965426,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.8858739,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"meeting-detector","depth":27,"bounds":{"left":0.025930852,"top":0.8858739,"width":0.03557181,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.9034318,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"mindfulmama","depth":27,"bounds":{"left":0.025930852,"top":0.9034318,"width":0.027260639,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.92098963,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"n8n","depth":27,"bounds":{"left":0.025930852,"top":0.92098963,"width":0.0076462766,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.9385475,"width":0.005319149,"height":0.008778931},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"notifier-app","depth":27,"bounds":{"left":0.025930852,"top":0.9385475,"width":0.023603724,"height":0.008778931},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Outline Section","depth":21,"bounds":{"left":0.015957447,"top":0.9473264,"width":0.09940159,"height":0.017557861},"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.01662234,"top":0.9497207,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"OUTLINE","depth":22,"bounds":{"left":0.022606382,"top":0.9473264,"width":0.01662234,"height":0.017557861},"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"OUTLINE","depth":23,"bounds":{"left":0.022606382,"top":0.95131683,"width":0.01662234,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Timeline Section","depth":21,"bounds":{"left":0.015957447,"top":0.9648843,"width":0.09940159,"height":0.017557861},"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.01662234,"top":0.96727854,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"TIMELINE","depth":22,"bounds":{"left":0.022606382,"top":0.9648843,"width":0.01761968,"height":0.017557861},"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"TIMELINE","depth":23,"bounds":{"left":0.022606382,"top":0.9688747,"width":0.01761968,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"docker-compose.yml, Editor Group 1","depth":28,"bounds":{"left":0.11569149,"top":0.047885075,"width":0.09773936,"height":0.02793296},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"docker-compose.yml, Editor Group 1","depth":28,"bounds":{"left":0.21343085,"top":0.047885075,"width":0.09607713,"height":0.02793296},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"docker-compose.yml, Editor Group 1","depth":28,"bounds":{"left":0.30950797,"top":0.047885075,"width":0.07280585,"height":0.02793296},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"","depth":29,"bounds":{"left":0.12965426,"top":0.07821229,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"services:\n\n postgresql:\n image: docker.io/library/postgres:16-alpine\n container_name: Authentik-DB\n hostname: authentik-db\n restart: unless-stopped\n security_opt:\n - no-new-privileges:true\n healthcheck:\n test: [\"CMD-SHELL\", \"pg_isready -d ${POSTGRES_DB:-authentik} -U ${POSTGRES_USER:-authentik}\"]\n interval: 5s\n timeout: 5s\n retries: 5\n environment:\n POSTGRES_PASSWORD: ${PG_PASS}\n POSTGRES_USER: authentik\n POSTGRES_DB: authentik\n volumes:\n - /volume2/docker/auth/db:/var/lib/postgresql/data\n networks:\n - authentik_internal\n\n redis:\n image: docker.io/library/redis:alpine\n container_name: Authentik-REDIS\n hostname: authentik-redis\n restart: unless-stopped\n security_opt:\n - no-new-privileges:true\n healthcheck:\n test: [\"CMD-SHELL\", \"redis-cli ping | grep PONG\"]\n interval: 5s\n timeout: 3s\n retries: 5\n networks:\n - authentik_internal\n\n server:\n image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG}\n container_name: Authentik-Server\n hostname: authentik-server\n restart: unless-stopped\n command: server\n environment:\n AUTHENTIK_REDIS__HOST: authentik-redis\n AUTHENTIK_POSTGRESQL__HOST: authentik-db\n AUTHENTIK_POSTGRESQL__USER: authentik\n AUTHENTIK_POSTGRESQL__NAME: authentik\n AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}\n AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}\n AUTHENTIK_ERROR_REPORTING__ENABLED: \"false\"\n AUTHENTIK_HOST: ${AUTHENTIK_HOST}\n AUTHENTIK_BOOTSTRAP_EMAIL: ${AUTHENTIK_BOOTSTRAP_EMAIL}\n AUTHENTIK_BOOTSTRAP_PASSWORD: ${AUTHENTIK_BOOTSTRAP_PASSWORD}\n ports:\n - \"9100:9000\"\n volumes:\n - /volume2/docker/auth/media:/media\n - /volume2/docker/auth/templates:/templates\n depends_on:\n postgresql:\n condition: service_healthy\n redis:\n condition: service_healthy\n networks:\n - authentik_internal\n - proxy\n\n worker:\n image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG}\n container_name: Authentik-Worker\n hostname: authentik-worker\n restart: unless-stopped\n command: worker\n user: root\n environment:\n AUTHENTIK_REDIS__HOST: authentik-redis\n AUTHENTIK_POSTGRESQL__HOST: authentik-db\n AUTHENTIK_POSTGRESQL__USER: authentik\n AUTHENTIK_POSTGRESQL__NAME: authentik\n AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}\n AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}\n volumes:\n - /var/run/docker.sock:/var/run/docker.sock\n - /volume2/docker/auth/media:/media\n - /volume2/docker/auth/certs:/certs\n - /volume2/docker/auth/templates:/templates\n depends_on:\n postgresql:\n condition: service_healthy\n redis:\n condition: service_healthy\n networks:\n - authentik_internal\n\n outpost:\n image: ghcr.io/goauthentik/proxy:${AUTHENTIK_TAG}\n container_name: Authentik-Outpost\n hostname: authentik-outpost\n restart: unless-stopped\n environment:\n AUTHENTIK_HOST: ${AUTHENTIK_HOST}\n AUTHENTIK_INSECURE: \"false\"\n AUTHENTIK_TOKEN: ${AUTHENTIK_OUTPOST_TOKEN}\n ports:\n - \"9101:9000\"\n depends_on:\n - server\n networks:\n - authentik_internal\n - proxy\n\nnetworks:\n authentik_internal:\n internal: true\n proxy:\n external: true","depth":28,"bounds":{"left":0.13763298,"top":0.105347164,"width":0.23803191,"height":0.014365523},"on_screen":true,"value":"services:\n\n postgresql:\n image: docker.io/library/postgres:16-alpine\n container_name: Authentik-DB\n hostname: authentik-db\n restart: unless-stopped\n security_opt:\n - no-new-privileges:true\n healthcheck:\n test: [\"CMD-SHELL\", \"pg_isready -d ${POSTGRES_DB:-authentik} -U ${POSTGRES_USER:-authentik}\"]\n interval: 5s\n timeout: 5s\n retries: 5\n environment:\n POSTGRES_PASSWORD: ${PG_PASS}\n POSTGRES_USER: authentik\n POSTGRES_DB: authentik\n volumes:\n - /volume2/docker/auth/db:/var/lib/postgresql/data\n networks:\n - authentik_internal\n\n redis:\n image: docker.io/library/redis:alpine\n container_name: Authentik-REDIS\n hostname: authentik-redis\n restart: unless-stopped\n security_opt:\n - no-new-privileges:true\n healthcheck:\n test: [\"CMD-SHELL\", \"redis-cli ping | grep PONG\"]\n interval: 5s\n timeout: 3s\n retries: 5\n networks:\n - authentik_internal\n\n server:\n image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG}\n container_name: Authentik-Server\n hostname: authentik-server\n restart: unless-stopped\n command: server\n environment:\n AUTHENTIK_REDIS__HOST: authentik-redis\n AUTHENTIK_POSTGRESQL__HOST: authentik-db\n AUTHENTIK_POSTGRESQL__USER: authentik\n AUTHENTIK_POSTGRESQL__NAME: authentik\n AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}\n AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}\n AUTHENTIK_ERROR_REPORTING__ENABLED: \"false\"\n AUTHENTIK_HOST: ${AUTHENTIK_HOST}\n AUTHENTIK_BOOTSTRAP_EMAIL: ${AUTHENTIK_BOOTSTRAP_EMAIL}\n AUTHENTIK_BOOTSTRAP_PASSWORD: ${AUTHENTIK_BOOTSTRAP_PASSWORD}\n ports:\n - \"9100:9000\"\n volumes:\n - /volume2/docker/auth/media:/media\n - /volume2/docker/auth/templates:/templates\n depends_on:\n postgresql:\n condition: service_healthy\n redis:\n condition: service_healthy\n networks:\n - authentik_internal\n - proxy\n\n worker:\n image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG}\n container_name: Authentik-Worker\n hostname: authentik-worker\n restart: unless-stopped\n command: worker\n user: root\n environment:\n AUTHENTIK_REDIS__HOST: authentik-redis\n AUTHENTIK_POSTGRESQL__HOST: authentik-db\n AUTHENTIK_POSTGRESQL__USER: authentik\n AUTHENTIK_POSTGRESQL__NAME: authentik\n AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}\n AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}\n volumes:\n - /var/run/docker.sock:/var/run/docker.sock\n - /volume2/docker/auth/media:/media\n - /volume2/docker/auth/certs:/certs\n - /volume2/docker/auth/templates:/templates\n depends_on:\n postgresql:\n condition: service_healthy\n redis:\n condition: service_healthy\n networks:\n - authentik_internal\n\n outpost:\n image: ghcr.io/goauthentik/proxy:${AUTHENTIK_TAG}\n container_name: Authentik-Outpost\n hostname: authentik-outpost\n restart: unless-stopped\n environment:\n AUTHENTIK_HOST: ${AUTHENTIK_HOST}\n AUTHENTIK_INSECURE: \"false\"\n AUTHENTIK_TOKEN: ${AUTHENTIK_OUTPOST_TOKEN}\n ports:\n - \"9101:9000\"\n depends_on:\n - server\n networks:\n - authentik_internal\n - proxy\n\nnetworks:\n authentik_internal:\n internal: true\n proxy:\n external: true","role_description":"editor","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"services:\n\n postgresql:\n image: docker.io/library/postgres:16-alpine\n container_name: Authentik-DB\n hostname: authentik-db\n restart: unless-stopped\n security_opt:\n - no-new-privileges:true\n healthcheck:\n test: [\"CMD-SHELL\", \"pg_isready -d ${POSTGRES_DB:-authentik} -U ${POSTGRES_USER:-authentik}\"]\n interval: 5s\n timeout: 5s\n retries: 5\n environment:\n POSTGRES_PASSWORD: ${PG_PASS}\n POSTGRES_USER: authentik\n POSTGRES_DB: authentik\n volumes:\n - /volume2/docker/auth/db:/var/lib/postgresql/data\n networks:\n - authentik_internal\n\n redis:\n image: docker.io/library/redis:alpine\n container_name: Authentik-REDIS\n hostname: authentik-redis\n restart: unless-stopped\n security_opt:\n - no-new-privileges:true\n healthcheck:\n test: [\"CMD-SHELL\", \"redis-cli ping | grep PONG\"]\n interval: 5s\n timeout: 3s\n retries: 5\n networks:\n - authentik_internal\n\n server:\n image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG}\n container_name: Authentik-Server\n hostname: authentik-server\n restart: unless-stopped\n command: server\n environment:\n AUTHENTIK_REDIS__HOST: authentik-redis\n AUTHENTIK_POSTGRESQL__HOST: authentik-db\n AUTHENTIK_POSTGRESQL__USER: authentik\n AUTHENTIK_POSTGRESQL__NAME: authentik\n AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}\n AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}\n AUTHENTIK_ERROR_REPORTING__ENABLED: \"false\"\n AUTHENTIK_HOST: ${AUTHENTIK_HOST}\n AUTHENTIK_BOOTSTRAP_EMAIL: ${AUTHENTIK_BOOTSTRAP_EMAIL}\n AUTHENTIK_BOOTSTRAP_PASSWORD: ${AUTHENTIK_BOOTSTRAP_PASSWORD}\n ports:\n - \"9100:9000\"\n volumes:\n - /volume2/docker/auth/media:/media\n - /volume2/docker/auth/templates:/templates\n depends_on:\n postgresql:\n condition: service_healthy\n redis:\n condition: service_healthy\n networks:\n - authentik_internal\n - proxy\n\n worker:\n image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG}\n container_name: Authentik-Worker\n hostname: authentik-worker\n restart: unless-stopped\n command: worker\n user: root\n environment:\n AUTHENTIK_REDIS__HOST: authentik-redis\n AUTHENTIK_POSTGRESQL__HOST: authentik-db\n AUTHENTIK_POSTGRESQL__USER: authentik\n AUTHENTIK_POSTGRESQL__NAME: authentik\n AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}\n AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}\n volumes:\n - /var/run/docker.sock:/var/run/docker.sock\n - /volume2/docker/auth/media:/media\n - /volume2/docker/auth/certs:/certs\n - /volume2/docker/auth/templates:/templates\n depends_on:\n postgresql:\n condition: service_healthy\n redis:\n condition: service_healthy\n networks:\n - authentik_internal\n\n outpost:\n image: ghcr.io/goauthentik/proxy:${AUTHENTIK_TAG}\n container_name: Authentik-Outpost\n hostname: authentik-outpost\n restart: unless-stopped\n environment:\n AUTHENTIK_HOST: ${AUTHENTIK_HOST}\n AUTHENTIK_INSECURE: \"false\"\n AUTHENTIK_TOKEN: ${AUTHENTIK_OUTPOST_TOKEN}\n ports:\n - \"9101:9000\"\n depends_on:\n - server\n networks:\n - authentik_internal\n - proxy\n\nnetworks:\n authentik_internal:\n internal: true\n proxy:\n external: true","depth":29,"bounds":{"left":0.13763298,"top":0.10694334,"width":0.23803191,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Review payment logger au…, Editor Group 2","depth":28,"bounds":{"left":0.5578458,"top":0.047885075,"width":0.07679521,"height":0.02793296},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXRadioButton","text":"Problems (⇧⌘M)","depth":22,"bounds":{"left":0.118351065,"top":0.7278532,"width":0.027925532,"height":0.02793296},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"PROBLEMS","depth":24,"bounds":{"left":0.122340426,"top":0.7366321,"width":0.019946808,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Output (⇧⌘U)","depth":22,"bounds":{"left":0.14594415,"top":0.7278532,"width":0.023603724,"height":0.02793296},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUTPUT","depth":24,"bounds":{"left":0.14993352,"top":0.7366321,"width":0.015625,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Debug Console (⇧⌘Y)","depth":22,"bounds":{"left":0.16921543,"top":0.7278532,"width":0.039893616,"height":0.02793296},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DEBUG CONSOLE","depth":24,"bounds":{"left":0.1732048,"top":0.7366321,"width":0.031914894,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Terminal (⌃`)","depth":22,"bounds":{"left":0.2087766,"top":0.7278532,"width":0.026595745,"height":0.02793296},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":true},{"role":"AXStaticText","text":"TERMINAL","depth":24,"bounds":{"left":0.21276596,"top":0.7366321,"width":0.01861702,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Ports","depth":22,"bounds":{"left":0.23537233,"top":0.7278532,"width":0.020279255,"height":0.02793296},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"PORTS","depth":24,"bounds":{"left":0.2393617,"top":0.7366321,"width":0.012300532,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"remote SSH: nas","depth":16,"bounds":{"left":0.0006648936,"top":0.98244214,"width":0.028590426,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.0033244682,"top":0.9848364,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"SSH: nas","depth":17,"bounds":{"left":0.008643617,"top":0.9856345,"width":0.017952127,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"location-logger (Git)","depth":16,"bounds":{"left":0.030917553,"top":0.98244214,"width":0.03756649,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.031914894,"top":0.9848364,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"location-logger","depth":17,"bounds":{"left":0.03723404,"top":0.9856345,"width":0.03025266,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"location-logger (Git) - main*, Checkout Branch/Tag...","depth":16,"bounds":{"left":0.06815159,"top":0.98244214,"width":0.019614361,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.069148935,"top":0.9848364,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"main*","depth":17,"bounds":{"left":0.07446808,"top":0.9856345,"width":0.012300532,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"location-logger (Git) - Synchronize Changes","depth":16,"bounds":{"left":0.08743351,"top":0.98244214,"width":0.0076462766,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"No Problems","depth":16,"bounds":{"left":0.09740692,"top":0.98244214,"width":0.022606382,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.09906915,"top":0.9848364,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"0","depth":17,"bounds":{"left":0.1043883,"top":0.9856345,"width":0.004986702,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.109042555,"top":0.9848364,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"0","depth":17,"bounds":{"left":0.1143617,"top":0.9856345,"width":0.0039893617,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"No Ports Forwarded","depth":16,"bounds":{"left":0.12167553,"top":0.98244214,"width":0.012632979,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.12333777,"top":0.9848364,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"0","depth":17,"bounds":{"left":0.12865691,"top":0.9856345,"width":0.0039893617,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Notifications","depth":16,"bounds":{"left":0.9886968,"top":0.98244214,"width":0.010638298,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sign In","depth":16,"bounds":{"left":0.9650931,"top":0.98244214,"width":0.022606382,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.96675533,"top":0.9848364,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Sign In","depth":17,"bounds":{"left":0.97207445,"top":0.9856345,"width":0.013962766,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"expanded","depth":12,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Command Succeeded","depth":12,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Review payment logger authorization implementation","depth":19,"bounds":{"left":0.56017286,"top":0.08060654,"width":0.099734046,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Session history","depth":19,"bounds":{"left":0.9780585,"top":0.08060654,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"Session history","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New session","depth":19,"bounds":{"left":0.9886968,"top":0.08060654,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"New session","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Message actions","depth":24,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"review payment_logger project how toes authorization work","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Let me explore the payment_logger project structure first.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Find payment_logger project files","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker -type f -name \"*.py\" -o -name \"*.yml\" -o -name \"*.yaml\" -o -name \"*.env\" -o -name \"*.toml\" -o -name \"*.cfg\" | grep -i payment | head -50","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"bfs: error: /volume2/docker/portnotedb/pg_commit_ts: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_dynshmem: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_notify: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_serial: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_snapshots: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_subtrans: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_twophase: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_multixact: Permission denied.\nbfs: error: /volume2/docker/portnotedb/base: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_replslot: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_tblspc: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_stat: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_stat_tmp: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_xact: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_logical: Permission denied.\nbfs: error: /volume2/docker/openttd/.dbus: Permission denied.\nbfs: error: /volume2/docker/immich/db: Permission denied.\nbfs: error: /volume2/docker/paperlessngx/db: Permission denied.\nbfs: error: /volume2/docker/appflowy/postgres: Permission denied.\nbfs: error: /volume2/docker/auth/db: Permission denied.\nbfs: error: /volume2/docker/openttd/.XDG/dbus-1: Permission denied.\nbfs: error: /volume2/docker/openttd/.config/pulse: Permission denied.\nbfs: error: /volume2/docker/openttd/.cache/openbox/sessions: Permission denied.\n/volume2/docker/payments-logger/.env\n/volume2/docker/payments-logger/docker-compose.yml\n/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"List docker directory contents","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ls /volume2/docker/","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"adguard\nai-stack\napp-db\nappflowy\naudiobookshelf\nauth\nbeszel\nbitwarden\ndawarich\ndsk-uploader\nflask-app\ngarmin-connector\ngitea\nhealth\nhealth-tracker\nhomarr\nhst\nimmich\njellyfinht\nkavita\nlibreoffice\nlinkwarden\nlocation-logger\nmariadb\nmeeting-detector\nmindfulmama\nn8n\nnotifier-app\nnpm\noauth\nobsidian\nollama\nopenttd\nopenvpn-client\nopen-webui\norchestrator\noutfit-app\nowntracks-stack\npaperlessngx\npayments-logger\npersonal-log\npersonal-log-system\nplayer\nportainer\nportnotedb\nreminders-app\nromm\nsecond-brain\nstatic\nstirling\nsyncthing\ntailscale\ntemp-logger\ntest-app\ntmp\ntorrent-stack\ntree\ntrilium\ntubearchivist\ntwenty\nuptimekuma\nytptube","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Agent:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore payment_logger authorization code","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore the payments-logger project at /volume2/docker/payments-logger and give me a thorough understanding of how authorization works. I need to know:\n\n1. What auth mechanism is used (JWT, sessions, API keys, OAuth, etc.)\n2. Where auth is enforced (middleware, decorators, route guards, etc.)\n3. What roles/permissions exist\n4. How tokens are issued, validated, and refreshed\n5. Any auth-related config (env vars, settings)\n\nPlease read the key source files and give me a clear summary with file paths and line numbers for the important parts.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/payments-logger -type f -name \"*.py\" -o -name \"*.json\" -o -name \"*.yml\" -o -name \"*.yaml\" | grep -E \"(auth|token|jwt|session|permission|role)\" | head -20","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(Bash completed with no output)","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ls -la /volume2/docker/payments-logger/ 2>/dev/null || echo \"Directory not found\"","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"total 36\ndrwxrwxrwx 1 Adm1n admin 162 Mar 29 18:01 .\ndrwxrwxrwx 1 root root 1146 Apr 26 18:49 ..\n-rwxrwxrwx 1 Adm1n admin 15233 Feb 22 17:08 API.md\ndrwxrwxrwx 1 Adm1n admin 88 Mar 29 15:41 backend\ndrwxrwxrwx 1 Adm1n admin 38 Mar 29 17:07 .claude\n-rwxrwxrwx 1 Adm1n admin 1502 Mar 29 18:01 docker-compose.yml\n-rwxrwxrwx 1 Adm1n admin 1066 Mar 29 15:44 .env\n-rwxrwxrwx 1 Adm1n admin 1078 Feb 14 17:53 .env.example\ndrwxrwxrwx 1 Adm1n admin 194 Mar 29 15:44 frontend\n-rwxrwxrwx 1 Adm1n admin 19 Feb 14 17:54 .gitignore\n-rwxrwxrwx 1 Adm1n admin 4052 Feb 14 19:06 README.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/payments-logger/backend -type f | head -30","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/payments-logger/backend/Dockerfile\n/volume2/docker/payments-logger/backend/.dockerignore\n/volume2/docker/payments-logger/backend/package.json\n/volume2/docker/payments-logger/backend/prisma/schema.prisma\n/volume2/docker/payments-logger/backend/src/parser.js\n/volume2/docker/payments-logger/backend/src/index.js\n/volume2/docker/payments-logger/backend/src/auth.js\n/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml\n/volume2/docker/payments-logger/backend/src/routes/payments.js\n/volume2/docker/payments-logger/backend/prisma/migrations/20260210_init/migration.sql\n/volume2/docker/payments-logger/backend/prisma/migrations/20260210_simplify/migration.sql\n/volume2/docker/payments-logger/backend/prisma/migrations/20260222_add_card/migration.sql","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/payments-logger -type f \\( -name \"*.js\" -o -name \"*.json\" -o -name \"*.md\" \\) | sort","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/payments-logger/API.md\n/volume2/docker/payments-logger/backend/package.json\n/volume2/docker/payments-logger/backend/src/auth.js\n/volume2/docker/payments-logger/backend/src/index.js\n/volume2/docker/payments-logger/backend/src/parser.js\n/volume2/docker/payments-logger/backend/src/routes/payments.js\n/volume2/docker/payments-logger/.claude/settings.local.json\n/volume2/docker/payments-logger/frontend/package.json\n/volume2/docker/payments-logger/frontend/postcss.config.js\n/volume2/docker/payments-logger/frontend/src/auth.js\n/volume2/docker/payments-logger/frontend/tailwind.config.js\n/volume2/docker/payments-logger/frontend/vite.config.js\n/volume2/docker/payments-logger/README.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"auth.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"auth.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"index.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"index.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"package.json","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"package.json","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"auth.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"auth.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"API.md","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"API.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"payments.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"payments.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env.example","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env.example","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"schema.prisma","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"schema.prisma","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"grep -r \"API_KEY\\|auth\\|token\\|oauth\\|hydra\" /volume2/docker/payments-logger/backend/src --include=\"*.js\" -n","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/payments-logger/backend/src/index.js:6:const { bearerTokenMiddleware, wellKnownRouter } = require('./auth');\n/volume2/docker/payments-logger/backend/src/index.js:18:// ── OAuth Bearer token auth (skips public paths) ──────────────────────────────\n/volume2/docker/payments-logger/backend/src/auth.js:2: * OAuth 2.1 / Hydra JWT authentication for Express.\n/volume2/docker/payments-logger/backend/src/auth.js:6: * - wellKnownRouter — serves /.well-known/oauth-* discovery endpoints\n/volume2/docker/payments-logger/backend/src/auth.js:33:function sendUnauthorized(res, detail, error = 'invalid_token') {\n/volume2/docker/payments-logger/backend/src/auth.js:39: `resource_metadata=\"${realm}/.well-known/oauth-protected-resource\"`,\n/volume2/docker/payments-logger/backend/src/auth.js:40: `authorization_server=\"${HYDRA_PUBLIC_URL}\"`,\n/volume2/docker/payments-logger/backend/src/auth.js:52: * On success, attaches the decoded payload to req.tokenPayload.\n/volume2/docker/payments-logger/backend/src/auth.js:54: * @param {Set<string>} publicPaths Paths to skip auth for.\n/volume2/docker/payments-logger/backend/src/auth.js:58: '/.well-known/oauth-protected-resource',\n/volume2/docker/payments-logger/backend/src/auth.js:59: '/.well-known/oauth-authorization-server',\n/volume2/docker/payments-logger/backend/src/auth.js:66: const auth = req.headers.authorization || '';\n/volume2/docker/payments-logger/backend/src/auth.js:67: if (!auth.toLowerCase().startsWith('bearer ')) {\n/volume2/docker/payments-logger/backend/src/auth.js:68: return sendUnauthorized(res, 'Bearer token required', 'invalid_request');\n/volume2/docker/payments-logger/backend/src/auth.js:71: const token = auth.slice(7).trim();\n/volume2/docker/payments-logger/backend/src/auth.js:72: if (!token) {\n/volume2/docker/payments-logger/backend/src/auth.js:73: return sendUnauthorized(res, 'Bearer token required', 'invalid_request');\n/volume2/docker/payments-logger/backend/src/auth.js:82: const { payload } = await jwtVerify(token, getJwks(), verifyOptions);\n/volume2/docker/payments-logger/backend/src/auth.js:83: req.tokenPayload = payload;\n/volume2/docker/payments-logger/backend/src/auth.js:87: const error = msg.includes('expired') ? 'invalid_token' : 'invalid_token';\n/volume2/docker/payments-logger/backend/src/auth.js:88: sendUnauthorized(res, msg, error);\n/volume2/docker/payments-logger/backend/src/auth.js:98:wellKnownRouter.get('/.well-known/oauth-protected-resource', (_req, res) => {\n/volume2/docker/payments-logger/backend/src/auth.js:103: authorization_servers: [HYDRA_PUBLIC_URL],\n/volume2/docker/payments-logger/backend/src/auth.js:111:wellKnownRouter.get('/.well-known/oauth-authorization-server', async (_req, res) => {\n/volume2/docker/payments-logger/backend/src/auth.js:119: authorization_endpoint: doc.authorization_endpoint,\n/volume2/docker/payments-logger/backend/src/auth.js:120: token_endpoint: doc.token_endpoint,\n/volume2/docker/payments-logger/backend/src/auth.js:123: grant_types_supported: doc.grant_types_supported || ['authorization_code', 'refresh_token'],\n/volume2/docker/payments-logger/backend/src/auth.js:124: token_endpoint_auth_methods_supported: doc.token_endpoint_auth_methods_supported || ['none', 'client_secret_basic'],\n/volume2/docker/payments-logger/backend/src/auth.js:128: id_token_signing_alg_values_supported: doc.id_token_signing_alg_values_supported || ['RS256'],\n/volume2/docker/payments-logger/backend/src/routes/payments.js:58:// ── Ingest a payment (public — no auth) ──────────────────────────────────────","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/payments-logger/frontend/src -type f -name \"*.js\" -o -name \"*.jsx\" -o -name \"*.ts\" -o -name \"*.tsx\" | head -20","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/payments-logger/frontend/src/main.jsx\n/volume2/docker/payments-logger/frontend/src/App.jsx\n/volume2/docker/payments-logger/frontend/src/auth.js\n/volume2/docker/payments-logger/frontend/src/components/PaymentCard.jsx\n/volume2/docker/payments-logger/frontend/src/components/PaymentList.jsx\n/volume2/docker/payments-logger/frontend/src/components/FilterBar.jsx\n/volume2/docker/payments-logger/frontend/src/components/PaymentTable.jsx\n/volume2/docker/payments-logger/frontend/src/components/AuthProvider.jsx\n/volume2/docker/payments-logger/frontend/src/components/AuthCallback.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"AuthProvider.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"AuthProvider.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"AuthCallback.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"AuthCallback.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"App.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"App.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"main.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"main.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"vite.config.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"vite.config.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"grep -r \"HYDRA\\|VITE\" /volume2/docker/payments-logger --include=\".env*\" -n","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(Bash completed with no output)","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"docker-compose.yml","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"docker-compose.yml","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"grep -r \"API_KEY\" /volume2/docker/payments-logger/backend --include=\"*.js\" -n","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(Bash completed with no output)","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"README.md","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"README.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"grep -n \"HYDRA\\|oauth\\|TOKEN\" /volume2/docker/payments-logger/backend/src/index.js /volume2/docker/payments-logger/backend/src/auth.js | head -40","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/payments-logger/backend/src/auth.js:6: * - wellKnownRouter — serves /.well-known/oauth-* discovery endpoints\n/volume2/docker/payments-logger/backend/src/auth.js:11:const HYDRA_PUBLIC_URL = (process.env.HYDRA_PUBLIC_URL || '').replace(/\\/$/, '');\n/volume2/docker/payments-logger/backend/src/auth.js:24: new URL(`${HYDRA_PUBLIC_URL}/.well-known/jwks.json`)\n/volume2/docker/payments-logger/backend/src/auth.js:39: `resource_metadata=\"${realm}/.well-known/oauth-protected-resource\"`,\n/volume2/docker/payments-logger/backend/src/auth.js:40: `authorization_server=\"${HYDRA_PUBLIC_URL}\"`,\n/volume2/docker/payments-logger/backend/src/auth.js:58: '/.well-known/oauth-protected-resource',\n/volume2/docker/payments-logger/backend/src/auth.js:59: '/.well-known/oauth-authorization-server',\n/volume2/docker/payments-logger/backend/src/auth.js:78: issuer: HYDRA_PUBLIC_URL,\n/volume2/docker/payments-logger/backend/src/auth.js:81: if (process.env.TOKEN_AUDIENCE) verifyOptions.audience = process.env.TOKEN_AUDIENCE;\n/volume2/docker/payments-logger/backend/src/auth.js:98:wellKnownRouter.get('/.well-known/oauth-protected-resource', (_req, res) => {\n/volume2/docker/payments-logger/backend/src/auth.js:103: authorization_servers: [HYDRA_PUBLIC_URL],\n/volume2/docker/payments-logger/backend/src/auth.js:107: jwks_uri: `${HYDRA_PUBLIC_URL}/.well-known/jwks.json`,\n/volume2/docker/payments-logger/backend/src/auth.js:111:wellKnownRouter.get('/.well-known/oauth-authorization-server', async (_req, res) => {\n/volume2/docker/payments-logger/backend/src/auth.js:113: const r = await fetch(`${HYDRA_PUBLIC_URL}/.well-known/openid-configuration`);\n/volume2/docker/payments-logger/backend/src/auth.js:118: issuer: doc.issuer || HYDRA_PUBLIC_URL,","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"payments-logger Authorization Overview","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"payments-logger Authorization Overview","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"The project uses","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"OAuth 2.1 with PKCE","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"via an external Hydra OAuth server at","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"hydra.lakylak.xyz","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Auth Flow","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Auth Flow","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Frontend","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"frontend/src/auth.js","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"frontend/src/auth.js","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"):","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Fetches OAuth server metadata via discovery endpoint","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Generates a PKCE code verifier/challenge (SHA-256)","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Redirects user to Hydra login with","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"code_challenge","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"On callback, exchanges code + verifier for tokens","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Stores","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"access_token","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"refresh_token","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"in","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"localStorage","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"pl_oauth_tokens","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":")","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Auto-refreshes token 30 seconds before expiry","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Backend","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"backend/src/auth.js","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"backend/src/auth.js","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"):","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"bearerTokenMiddleware","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"validates the","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Authorization: Bearer <token>","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"header","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Fetches Hydra's JWKS (cached 300s) and verifies JWT signature (RS256/ES256/PS256)","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Validates issuer (","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"https://hydra.lakylak.xyz","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":") and optional audience","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Enforcement","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Enforcement","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Applied globally in","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"backend/src/index.js:19","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"backend/src/index.js:19","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"with these","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"public (unprotected) paths","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":":","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/.well-known/oauth-protected-resource","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/.well-known/oauth-authorization-server","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/api/health","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/api/payments/ingest","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(rate-limited at 200 req/min — for SMS ingestion)","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Roles/Permissions","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Roles/Permissions","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"No RBAC","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— it's binary: authenticated vs. unauthenticated. Required scopes:","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"openid","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"offline_access","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Key Security Notes","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Key Security Notes","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PKCE","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"prevents authorization code interception","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"State parameter","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"provides CSRF protection","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"No server-side token storage","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— validation is stateless via JWKS","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"The README/API docs mention an","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"X-API-Key","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"header, but that's","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"outdated","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— the actual code uses Bearer tokens only","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Config lives in","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"docker-compose.yml","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"docker-compose.yml","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(lines 30–33):","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HYDRA_PUBLIC_URL","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"REQUIRED_SCOPES","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"OAUTH_CLIENT_ID","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", and optionally","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TOKEN_AUDIENCE","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"JWKS_CACHE_TTL","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Message actions","depth":24,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"compare it to location logger and make it the same. Lets remove hydra and only use authentic (or whatever location logger uses).","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Let me first explore how location-logger handles authorization.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Agent:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore location-logger authorization code","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore the location-logger project at /volume2/docker/location-logger and give me a thorough understanding of how authorization works. I need to know:\n\n1. What auth mechanism is used (JWT, sessions, API keys, OAuth, etc.)\n2. Where auth is enforced (middleware, decorators, route guards, etc.)\n3. What roles/permissions exist\n4. How tokens are issued, validated, and refreshed\n5. Any auth-related config (env vars, settings)\n6. Frontend auth flow (how the user logs in, how tokens are stored and used)\n7. The full directory/file structure of the project\n\nPlease read ALL relevant source files completely and give me a detailed summary with file paths and line numbers. I need enough detail to replicate this auth system in another project.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/location-logger -type f -name \"*.py\" -o -name \"*.js\" -o -name \"*.ts\" -o -name \"*.json\" | head -50","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/location-logger/.mcp.json\n/volume2/docker/location-logger/app/__init__.py\n/volume2/docker/location-logger/app/utils.py\n/volume2/docker/location-logger/app/config.py\n/volume2/docker/location-logger/app/main.py\n/volume2/docker/location-logger/alembic/env.py\n/volume2/docker/location-logger/mcp-server/server.py\n/volume2/docker/location-logger/alembic/versions/20260203_201500_create_location_points_table.py\n/volume2/docker/location-logger/alembic/versions/20260209_200000_add_enhanced_fields_and_tables.py\n/volume2/docker/location-logger/alembic/versions/20260214_000000_add_users_and_audit_logs.py\n/volume2/docker/location-logger/alembic/versions/20260320_000000_add_audit_query_string.py\n/volume2/docker/location-logger/app/services/geofence_service.py\n/volume2/docker/location-logger/app/services/recorder_service.py\n/volume2/docker/location-logger/app/services/trip_service.py\n/volume2/docker/location-logger/app/services/enhanced_location_service.py\n/volume2/docker/location-logger/app/services/geocoding_service.py\n/volume2/docker/location-logger/app/clients/__init__.py\n/volume2/docker/location-logger/app/clients/dawarich_client.py\n/volume2/docker/location-logger/app/clients/owntracks_client.py\n/volume2/docker/location-logger/app/models/areas.py\n/volume2/docker/location-logger/app/models/geofence_events.py\n/volume2/docker/location-logger/app/models/trips.py\n/volume2/docker/location-logger/app/models/user.py\n/volume2/docker/location-logger/app/models/location.py\n/volume2/docker/location-logger/app/models/audit_log.py\n/volume2/docker/location-logger/app/auth/__init__.py\n/volume2/docker/location-logger/app/auth/dependencies.py\n/volume2/docker/location-logger/app/auth/utils.py\n/volume2/docker/location-logger/app/api/enhanced_endpoints.py\n/volume2/docker/location-logger/app/db/base.py\n/volume2/docker/location-logger/app/db/session.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"tree -L 4 /volume2/docker/location-logger 2>/dev/null || find /volume2/docker/location-logger -type d | sort","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/location-logger\n├── alembic\n│ ├── env.py\n│ ├── script.py.mako\n│ └── versions\n│ ├── 20260203_201500_create_location_points_table.py\n│ ├── 20260209_200000_add_enhanced_fields_and_tables.py\n│ ├── 20260214_000000_add_users_and_audit_logs.py\n│ ├── 20260320_000000_add_audit_query_string.py\n│ └── __pycache__\n│ └── 20260214_000000_add_users_and_audit_logs.cpython-311.pyc\n├── alembic.ini\n├── app\n│ ├── api\n│ │ └── enhanced_endpoints.py\n│ ├── auth\n│ │ ├── dependencies.py\n│ │ ├── __init__.py\n│ │ ├── __pycache__\n│ │ │ ├── dependencies.cpython-311.pyc\n│ │ │ ├── __init__.cpython-311.pyc\n│ │ │ └── utils.cpython-311.pyc\n│ │ └── utils.py\n│ ├── clients\n│ │ ├── dawarich_client.py\n│ │ ├── __init__.py\n│ │ └── owntracks_client.py\n│ ├── config.py\n│ ├── db\n│ │ ├── base.py\n│ │ └── session.py\n│ ├── __init__.py\n│ ├── main.py\n│ ├── models\n│ │ ├── areas.py\n│ │ ├── audit_log.py\n│ │ ├── geofence_events.py\n│ │ ├── location.py\n│ │ ├── __pycache__\n│ │ │ ├── audit_log.cpython-311.pyc\n│ │ │ └── user.cpython-311.pyc\n│ │ ├── trips.py\n│ │ └── user.py\n│ ├── __pycache__\n│ │ ├── __init__.cpython-311.pyc\n│ │ └── main.cpython-311.pyc\n│ ├── services\n│ │ ├── enhanced_location_service.py\n│ │ ├── geocoding_service.py\n│ │ ├── geofence_service.py\n│ │ ├── recorder_service.py\n│ │ └── trip_service.py\n│ ├── static\n│ │ └── dashboard.html\n│ └── utils.py\n├── docker-compose.yml\n├── Dockerfile\n├── mcp-server\n│ ├── Dockerfile\n│ ├── requirements.txt\n│ └── server.py\n├── README.md\n├── requirements.txt\n└── today_map.html\n\n16 directories, 48 files","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"utils.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"utils.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"dependencies.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"dependencies.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"user.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"user.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"config.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"config.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"main.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"main.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"session.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"session.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"dashboard.html","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"dashboard.html","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"audit_log.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"audit_log.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"20260214_000000_add_users_and_audit_logs.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"20260214_000000_add_users_and_audit_logs.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"20260320_000000_add_audit_query_string.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"20260320_000000_add_audit_query_string.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"README.md","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"README.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"requirements.txt","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"requirements.txt","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"server.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"server.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"server.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"server.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(lines 101-400)","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Now I have a full picture of both systems. Let me read the payments-logger source files before planning the migration.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"List all payments-logger files","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/payments-logger -type f | grep -v node_modules | grep -v .git | sort","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/payments-logger/API.md\n/volume2/docker/payments-logger/backend/Dockerfile\n/volume2/docker/payments-logger/backend/.dockerignore\n/volume2/docker/payments-logger/backend/package.json\n/volume2/docker/payments-logger/backend/prisma/migrations/20260210_init/migration.sql\n/volume2/docker/payments-logger/backend/prisma/migrations/20260210_simplify/migration.sql\n/volume2/docker/payments-logger/backend/prisma/migrations/20260222_add_card/migration.sql\n/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml\n/volume2/docker/payments-logger/backend/prisma/schema.prisma\n/volume2/docker/payments-logger/backend/src/auth.js\n/volume2/docker/payments-logger/backend/src/index.js\n/volume2/docker/payments-logger/backend/src/parser.js\n/volume2/docker/payments-logger/backend/src/routes/payments.js\n/volume2/docker/payments-logger/.claude/settings.local.json\n/volume2/docker/payments-logger/docker-compose.yml\n/volume2/docker/payments-logger/.env\n/volume2/docker/payments-logger/.env.example\n/volume2/docker/payments-logger/frontend/Dockerfile\n/volume2/docker/payments-logger/frontend/.dockerignore\n/volume2/docker/payments-logger/frontend/index.html\n/volume2/docker/payments-logger/frontend/package.json\n/volume2/docker/payments-logger/frontend/postcss.config.js\n/volume2/docker/payments-logger/frontend/src/App.jsx\n/volume2/docker/payments-logger/frontend/src/auth.js\n/volume2/docker/payments-logger/frontend/src/components/AuthCallback.jsx\n/volume2/docker/payments-logger/frontend/src/components/AuthProvider.jsx\n/volume2/docker/payments-logger/frontend/src/components/FilterBar.jsx\n/volume2/docker/payments-logger/frontend/src/components/PaymentCard.jsx\n/volume2/docker/payments-logger/frontend/src/components/PaymentList.jsx\n/volume2/docker/payments-logger/frontend/src/components/PaymentTable.jsx\n/volume2/docker/payments-logger/frontend/src/index.css\n/volume2/docker/payments-logger/frontend/src/main.jsx\n/volume2/docker/payments-logger/frontend/tailwind.config.js\n/volume2/docker/payments-logger/frontend/vite.config.js\n/volume2/docker/payments-logger/README.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"auth.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"auth.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"index.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"index.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"auth.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"auth.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"AuthProvider.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"AuthProvider.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"package.json","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"package.json","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"AuthCallback.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"AuthCallback.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"schema.prisma","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"schema.prisma","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"docker-compose.yml","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"docker-compose.yml","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Now let me read the remaining frontend files.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"App.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"App.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"package.json","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"package.json","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Let me read the remaining files before making changes.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"main.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"main.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"vite.config.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"vite.config.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"payments.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"payments.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-8080334603972434754
|
-5421282858429984184
|
idle
|
accessibility
|
NULL
|
Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧ Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧G) - 55 pending changes
55
Run and Debug (⇧⌘D)
Remote Explorer
Extensions (⇧⌘X) - 2 require update
2
Claude Code
Containers
EXPLORER
EXPLORER
Explorer Section: docker [SSH: nas]
Explorer Section: docker [SSH: nas]
DOCKER [SSH: NAS]
adguard
ai-stack
app-db
appflowy
audiobookshelf
auth
certs
db
media
templates
.env
.env.example
docker-compose.yml
README.md
beszel
bitwarden
dawarich
dsk-uploader
flask-app
garmin-connector
gitea
health
health-tracker
homarr
hst
immich
jellyfinht
kavita
libreoffice
linkwarden
location-logger
alembic
app
mcp-server
.env
.env.example
.gitignore
.mcp.json
M
alembic.ini
docker-compose.yml
M
Dockerfile
README.md
M
requirements.txt
M
today_map.html
mariadb
meeting-detector
mindfulmama
n8n
notifier-app
Outline Section
OUTLINE
OUTLINE
Timeline Section
TIMELINE
TIMELINE
docker-compose.yml, Editor Group 1
docker-compose.yml, Editor Group 1
docker-compose.yml, Editor Group 1
services:
postgresql:
image: docker.io/library/postgres:16-alpine
container_name: Authentik-DB
hostname: authentik-db
restart: unless-stopped
security_opt:
- no-new-privileges:true
healthcheck:
test: ["CMD-SHELL", "pg_isready -d ${POSTGRES_DB:-authentik} -U ${POSTGRES_USER:-authentik}"]
interval: 5s
timeout: 5s
retries: 5
environment:
POSTGRES_PASSWORD: [PASSWORD]
POSTGRES_USER: authentik
POSTGRES_DB: authentik
volumes:
- /volume2/docker/auth/db:/var/lib/postgresql/data
networks:
- authentik_internal
redis:
image: docker.io/library/redis:alpine
container_name: Authentik-REDIS
hostname: authentik-redis
restart: unless-stopped
security_opt:
- no-new-privileges:true
healthcheck:
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
interval: 5s
timeout: 3s
retries: 5
networks:
- authentik_internal
server:
image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG}
container_name: Authentik-Server
hostname: authentik-server
restart: unless-stopped
command: server
environment:
AUTHENTIK_REDIS__HOST: authentik-redis
AUTHENTIK_POSTGRESQL__HOST: authentik-db
AUTHENTIK_POSTGRESQL__USER: authentik
AUTHENTIK_POSTGRESQL__NAME: authentik
AUTHENTIK_POSTGRESQL__PASSWORD: [PASSWORD]
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
AUTHENTIK_ERROR_REPORTING__ENABLED: "false"
AUTHENTIK_HOST: ${AUTHENTIK_HOST}
AUTHENTIK_BOOTSTRAP_EMAIL: ${AUTHENTIK_BOOTSTRAP_EMAIL}
AUTHENTIK_BOOTSTRAP_PASSWORD: [PASSWORD]
ports:
- "9100:9000"
volumes:
- /volume2/docker/auth/media:/media
- /volume2/docker/auth/templates:/templates
depends_on:
postgresql:
condition: service_healthy
redis:
condition: service_healthy
networks:
- authentik_internal
- proxy
worker:
image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG}
container_name: Authentik-Worker
hostname: authentik-worker
restart: unless-stopped
command: worker
user: root
environment:
AUTHENTIK_REDIS__HOST: authentik-redis
AUTHENTIK_POSTGRESQL__HOST: authentik-db
AUTHENTIK_POSTGRESQL__USER: authentik
AUTHENTIK_POSTGRESQL__NAME: authentik
AUTHENTIK_POSTGRESQL__PASSWORD: [PASSWORD]
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /volume2/docker/auth/media:/media
- /volume2/docker/auth/certs:/certs
- /volume2/docker/auth/templates:/templates
depends_on:
postgresql:
condition: service_healthy
redis:
condition: service_healthy
networks:
- authentik_internal
outpost:
image: ghcr.io/goauthentik/proxy:${AUTHENTIK_TAG}
container_name: Authentik-Outpost
hostname: authentik-outpost
restart: unless-stopped
environment:
AUTHENTIK_HOST: ${AUTHENTIK_HOST}
AUTHENTIK_INSECURE: "false"
AUTHENTIK_TOKEN: ${AUTHENTIK_OUTPOST_TOKEN}
ports:
- "9101:9000"
depends_on:
- server
networks:
- authentik_internal
- proxy
networks:
authentik_internal:
internal: true
proxy:
external: true
services:
postgresql:
image: docker.io/library/postgres:16-alpine
container_name: Authentik-DB
hostname: authentik-db
restart: unless-stopped
security_opt:
- no-new-privileges:true
healthcheck:
test: ["CMD-SHELL", "pg_isready -d ${POSTGRES_DB:-authentik} -U ${POSTGRES_USER:-authentik}"]
interval: 5s
timeout: 5s
retries: 5
environment:
POSTGRES_PASSWORD: [PASSWORD]
POSTGRES_USER: authentik
POSTGRES_DB: authentik
volumes:
- /volume2/docker/auth/db:/var/lib/postgresql/data
networks:
- authentik_internal
redis:
image: docker.io/library/redis:alpine
container_name: Authentik-REDIS
hostname: authentik-redis
restart: unless-stopped
security_opt:
- no-new-privileges:true
healthcheck:
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
interval: 5s
timeout: 3s
retries: 5
networks:
- authentik_internal
server:
image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG}
container_name: Authentik-Server
hostname: authentik-server
restart: unless-stopped
command: server
environment:
AUTHENTIK_REDIS__HOST: authentik-redis
AUTHENTIK_POSTGRESQL__HOST: authentik-db
AUTHENTIK_POSTGRESQL__USER: authentik
AUTHENTIK_POSTGRESQL__NAME: authentik
AUTHENTIK_POSTGRESQL__PASSWORD: [PASSWORD]
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
AUTHENTIK_ERROR_REPORTING__ENABLED: "false"
AUTHENTIK_HOST: ${AUTHENTIK_HOST}
AUTHENTIK_BOOTSTRAP_EMAIL: ${AUTHENTIK_BOOTSTRAP_EMAIL}
AUTHENTIK_BOOTSTRAP_PASSWORD: [PASSWORD]
ports:
- "9100:9000"
volumes:
- /volume2/docker/auth/media:/media
- /volume2/docker/auth/templates:/templates
depends_on:
postgresql:
condition: service_healthy
redis:
condition: service_healthy
networks:
- authentik_internal
- proxy
worker:
image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG}
container_name: Authentik-Worker
hostname: authentik-worker
restart: unless-stopped
command: worker
user: root
environment:
AUTHENTIK_REDIS__HOST: authentik-redis
AUTHENTIK_POSTGRESQL__HOST: authentik-db
AUTHENTIK_POSTGRESQL__USER: authentik
AUTHENTIK_POSTGRESQL__NAME: authentik
AUTHENTIK_POSTGRESQL__PASSWORD: [PASSWORD]
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /volume2/docker/auth/media:/media
- /volume2/docker/auth/certs:/certs
- /volume2/docker/auth/templates:/templates
depends_on:
postgresql:
condition: service_healthy
redis:
condition: service_healthy
networks:
- authentik_internal
outpost:
image: ghcr.io/goauthentik/proxy:${AUTHENTIK_TAG}
container_name: Authentik-Outpost
hostname: authentik-outpost
restart: unless-stopped
environment:
AUTHENTIK_HOST: ${AUTHENTIK_HOST}
AUTHENTIK_INSECURE: "false"
AUTHENTIK_TOKEN: ${AUTHENTIK_OUTPOST_TOKEN}
ports:
- "9101:9000"
depends_on:
- server
networks:
- authentik_internal
- proxy
networks:
authentik_internal:
internal: true
proxy:
external: true
Review payment logger au…, Editor Group 2
Problems (⇧⌘M)
PROBLEMS
Output (⇧⌘U)
OUTPUT
Debug Console (⇧⌘Y)
DEBUG CONSOLE
Terminal (⌃`)
TERMINAL
Ports
PORTS
remote SSH: nas
SSH: nas
location-logger (Git)
location-logger
location-logger (Git) - main*, Checkout Branch/Tag...
main*
location-logger (Git) - Synchronize Changes
No Problems
0
0
No Ports Forwarded
0
Notifications
Sign In
Sign In
expanded
Command Succeeded
Review payment logger authorization implementation
Session history
New session
Message actions
review payment_logger project how toes authorization work
Thinking
Thinking
Let me explore the payment_logger project structure first.
Bash
Find payment_logger project files
IN
find /volume2/docker -type f -name "*.py" -o -name "*.yml" -o -name "*.yaml" -o -name "*.env" -o -name "*.toml" -o -name "*.cfg" | grep -i payment | head -50
Copy code to clipboard
OUT
bfs: error: /volume2/docker/portnotedb/pg_commit_ts: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_dynshmem: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_notify: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_serial: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_snapshots: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_subtrans: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_twophase: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_multixact: Permission denied.
bfs: error: /volume2/docker/portnotedb/base: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_replslot: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_tblspc: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_stat: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_stat_tmp: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_xact: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_logical: Permission denied.
bfs: error: /volume2/docker/openttd/.dbus: Permission denied.
bfs: error: /volume2/docker/immich/db: Permission denied.
bfs: error: /volume2/docker/paperlessngx/db: Permission denied.
bfs: error: /volume2/docker/appflowy/postgres: Permission denied.
bfs: error: /volume2/docker/auth/db: Permission denied.
bfs: error: /volume2/docker/openttd/.XDG/dbus-1: Permission denied.
bfs: error: /volume2/docker/openttd/.config/pulse: Permission denied.
bfs: error: /volume2/docker/openttd/.cache/openbox/sessions: Permission denied.
/volume2/docker/payments-logger/.env
/volume2/docker/payments-logger/docker-compose.yml
/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml
Bash
List docker directory contents
IN
ls /volume2/docker/
Copy code to clipboard
OUT
adguard
ai-stack
app-db
appflowy
audiobookshelf
auth
beszel
bitwarden
dawarich
dsk-uploader
flask-app
garmin-connector
gitea
health
health-tracker
homarr
hst
immich
jellyfinht
kavita
libreoffice
linkwarden
location-logger
mariadb
meeting-detector
mindfulmama
n8n
notifier-app
npm
oauth
obsidian
ollama
openttd
openvpn-client
open-webui
orchestrator
outfit-app
owntracks-stack
paperlessngx
payments-logger
personal-log
personal-log-system
player
portainer
portnotedb
reminders-app
romm
second-brain
static
stirling
syncthing
tailscale
temp-logger
test-app
tmp
torrent-stack
tree
trilium
tubearchivist
twenty
uptimekuma
ytptube
Agent:
Explore payment_logger authorization code
IN
Explore the payments-logger project at /volume2/docker/payments-logger and give me a thorough understanding of how authorization works. I need to know:
1. What auth mechanism is used (JWT, sessions, API keys, OAuth, etc.)
2. Where auth is enforced (middleware, decorators, route guards, etc.)
3. What roles/permissions exist
4. How tokens are issued, validated, and refreshed
5. Any auth-related config (env vars, settings)
Please read the key source files and give me a clear summary with file paths and line numbers for the important parts.
Bash
IN
find /volume2/docker/payments-logger -type f -name "*.py" -o -name "*.json" -o -name "*.yml" -o -name "*.yaml" | grep -E "(auth|token|jwt|session|permission|role)" | head -20
Copy code to clipboard
OUT
(Bash completed with no output)
Bash
IN
ls -la /volume2/docker/payments-logger/ 2>/dev/null || echo "Directory not found"
Copy code to clipboard
OUT
total 36
drwxrwxrwx 1 Adm1n admin 162 Mar 29 18:01 .
drwxrwxrwx 1 root root 1146 Apr 26 18:49 ..
-rwxrwxrwx 1 Adm1n admin 15233 Feb 22 17:08 API.md
drwxrwxrwx 1 Adm1n admin 88 Mar 29 15:41 backend
drwxrwxrwx 1 Adm1n admin 38 Mar 29 17:07 .claude
-rwxrwxrwx 1 Adm1n admin 1502 Mar 29 18:01 docker-compose.yml
-rwxrwxrwx 1 Adm1n admin 1066 Mar 29 15:44 .env
-rwxrwxrwx 1 Adm1n admin 1078 Feb 14 17:53 .env.example
drwxrwxrwx 1 Adm1n admin 194 Mar 29 15:44 frontend
-rwxrwxrwx 1 Adm1n admin 19 Feb 14 17:54 .gitignore
-rwxrwxrwx 1 Adm1n admin 4052 Feb 14 19:06 README.md
Bash
IN
find /volume2/docker/payments-logger/backend -type f | head -30
Copy code to clipboard
OUT
/volume2/docker/payments-logger/backend/Dockerfile
/volume2/docker/payments-logger/backend/.dockerignore
/volume2/docker/payments-logger/backend/package.json
/volume2/docker/payments-logger/backend/prisma/schema.prisma
/volume2/docker/payments-logger/backend/src/parser.js
/volume2/docker/payments-logger/backend/src/index.js
/volume2/docker/payments-logger/backend/src/auth.js
/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml
/volume2/docker/payments-logger/backend/src/routes/payments.js
/volume2/docker/payments-logger/backend/prisma/migrations/20260210_init/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260210_simplify/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260222_add_card/migration.sql
Bash
IN
find /volume2/docker/payments-logger -type f \( -name "*.js" -o -name "*.json" -o -name "*.md" \) | sort
Copy code to clipboard
OUT
/volume2/docker/payments-logger/API.md
/volume2/docker/payments-logger/backend/package.json
/volume2/docker/payments-logger/backend/src/auth.js
/volume2/docker/payments-logger/backend/src/index.js
/volume2/docker/payments-logger/backend/src/parser.js
/volume2/docker/payments-logger/backend/src/routes/payments.js
/volume2/docker/payments-logger/.claude/settings.local.json
/volume2/docker/payments-logger/frontend/package.json
/volume2/docker/payments-logger/frontend/postcss.config.js
/volume2/docker/payments-logger/frontend/src/auth.js
/volume2/docker/payments-logger/frontend/tailwind.config.js
/volume2/docker/payments-logger/frontend/vite.config.js
/volume2/docker/payments-logger/README.md
Read
.env
.env
Read
auth.js
auth.js
Read
index.js
index.js
Read
package.json
package.json
Read
auth.js
auth.js
Read
API.md
API.md
Read
payments.js
payments.js
Read
.env.example
.env.example
Read
schema.prisma
schema.prisma
Bash
IN
grep -r "API_KEY\|auth\|token\|oauth\|hydra" /volume2/docker/payments-logger/backend/src --include="*.js" -n
Copy code to clipboard
OUT
/volume2/docker/payments-logger/backend/src/index.js:6:const { bearerTokenMiddleware, wellKnownRouter } = require('./auth');
/volume2/docker/payments-logger/backend/src/index.js:18:// ── OAuth Bearer token auth (skips public paths) ──────────────────────────────
/volume2/docker/payments-logger/backend/src/auth.js:2: * OAuth 2.1 / Hydra JWT authentication for Express.
/volume2/docker/payments-logger/backend/src/auth.js:6: * - wellKnownRouter — serves /.well-known/oauth-* discovery endpoints
/volume2/docker/payments-logger/backend/src/auth.js:33:function sendUnauthorized(res, detail, error = 'invalid_token') {
/volume2/docker/payments-logger/backend/src/auth.js:39: `resource_metadata="${realm}/.well-known/oauth-protected-resource"`,
/volume2/docker/payments-logger/backend/src/auth.js:40: `authorization_server="${HYDRA_PUBLIC_URL}"`,
/volume2/docker/payments-logger/backend/src/auth.js:52: * On success, attaches the decoded payload to req.tokenPayload.
/volume2/docker/payments-logger/backend/src/auth.js:54: * @param {Set<string>} publicPaths Paths to skip auth for.
/volume2/docker/payments-logger/backend/src/auth.js:58: '/.well-known/oauth-protected-resource',
/volume2/docker/payments-logger/backend/src/auth.js:59: '/.well-known/oauth-authorization-server',
/volume2/docker/payments-logger/backend/src/auth.js:66: const auth = req.headers.authorization || '';
/volume2/docker/payments-logger/backend/src/auth.js:67: if (!auth.toLowerCase().startsWith('bearer ')) {
/volume2/docker/payments-logger/backend/src/auth.js:68: return sendUnauthorized(res, 'Bearer token required', 'invalid_request');
/volume2/docker/payments-logger/backend/src/auth.js:71: const token = auth.slice(7).trim();
/volume2/docker/payments-logger/backend/src/auth.js:72: if (!token) {
/volume2/docker/payments-logger/backend/src/auth.js:73: return sendUnauthorized(res, 'Bearer token required', 'invalid_request');
/volume2/docker/payments-logger/backend/src/auth.js:82: const { payload } = await jwtVerify(token, getJwks(), verifyOptions);
/volume2/docker/payments-logger/backend/src/auth.js:83: req.tokenPayload = payload;
/volume2/docker/payments-logger/backend/src/auth.js:87: const error = msg.includes('expired') ? 'invalid_token' : 'invalid_token';
/volume2/docker/payments-logger/backend/src/auth.js:88: sendUnauthorized(res, msg, error);
/volume2/docker/payments-logger/backend/src/auth.js:98:wellKnownRouter.get('/.well-known/oauth-protected-resource', (_req, res) => {
/volume2/docker/payments-logger/backend/src/auth.js:103: authorization_servers: [HYDRA_PUBLIC_URL],
/volume2/docker/payments-logger/backend/src/auth.js:111:wellKnownRouter.get('/.well-known/oauth-authorization-server', async (_req, res) => {
/volume2/docker/payments-logger/backend/src/auth.js:119: authorization_endpoint: doc.authorization_endpoint,
/volume2/docker/payments-logger/backend/src/auth.js:120: token_endpoint: doc.token_endpoint,
/volume2/docker/payments-logger/backend/src/auth.js:123: grant_types_supported: doc.grant_types_supported || ['authorization_code', 'refresh_token'],
/volume2/docker/payments-logger/backend/src/auth.js:124: [API_KEY]: doc.[API_KEY] || ['none', 'client_secret_basic'],
/volume2/docker/payments-logger/backend/src/auth.js:128: id_token_signing_alg_values_supported: doc.id_token_signing_alg_values_supported || ['RS256'],
/volume2/docker/payments-logger/backend/src/routes/payments.js:58:// ── Ingest a payment (public — no auth) ──────────────────────────────────────
Bash
IN
find /volume2/docker/payments-logger/frontend/src -type f -name "*.js" -o -name "*.jsx" -o -name "*.ts" -o -name "*.tsx" | head -20
Copy code to clipboard
OUT
/volume2/docker/payments-logger/frontend/src/main.jsx
/volume2/docker/payments-logger/frontend/src/App.jsx
/volume2/docker/payments-logger/frontend/src/auth.js
/volume2/docker/payments-logger/frontend/src/components/PaymentCard.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentList.jsx
/volume2/docker/payments-logger/frontend/src/components/FilterBar.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentTable.jsx
/volume2/docker/payments-logger/frontend/src/components/AuthProvider.jsx
/volume2/docker/payments-logger/frontend/src/components/AuthCallback.jsx
Read
AuthProvider.jsx
AuthProvider.jsx
Read
AuthCallback.jsx
AuthCallback.jsx
Read
App.jsx
App.jsx
Read
main.jsx
main.jsx
Read
vite.config.js
vite.config.js
Bash
IN
grep -r "HYDRA\|VITE" /volume2/docker/payments-logger --include=".env*" -n
Copy code to clipboard
OUT
(Bash completed with no output)
Read
docker-compose.yml
docker-compose.yml
Bash
IN
grep -r "API_KEY" /volume2/docker/payments-logger/backend --include="*.js" -n
Copy code to clipboard
OUT
(Bash completed with no output)
Read
README.md
README.md
Bash
IN
grep -n "HYDRA\|oauth\|TOKEN" /volume2/docker/payments-logger/backend/src/index.js /volume2/docker/payments-logger/backend/src/auth.js | head -40
Copy code to clipboard
OUT
/volume2/docker/payments-logger/backend/src/auth.js:6: * - wellKnownRouter — serves /.well-known/oauth-* discovery endpoints
/volume2/docker/payments-logger/backend/src/auth.js:11:const HYDRA_PUBLIC_URL = (process.env.HYDRA_PUBLIC_URL || '').replace(/\/$/, '');
/volume2/docker/payments-logger/backend/src/auth.js:24: new URL(`${HYDRA_PUBLIC_URL}/.well-known/jwks.json`)
/volume2/docker/payments-logger/backend/src/auth.js:39: `resource_metadata="${realm}/.well-known/oauth-protected-resource"`,
/volume2/docker/payments-logger/backend/src/auth.js:40: `authorization_server="${HYDRA_PUBLIC_URL}"`,
/volume2/docker/payments-logger/backend/src/auth.js:58: '/.well-known/oauth-protected-resource',
/volume2/docker/payments-logger/backend/src/auth.js:59: '/.well-known/oauth-authorization-server',
/volume2/docker/payments-logger/backend/src/auth.js:78: issuer: HYDRA_PUBLIC_URL,
/volume2/docker/payments-logger/backend/src/auth.js:81: if (process.env.TOKEN_AUDIENCE) verifyOptions.audience = process.env.TOKEN_AUDIENCE;
/volume2/docker/payments-logger/backend/src/auth.js:98:wellKnownRouter.get('/.well-known/oauth-protected-resource', (_req, res) => {
/volume2/docker/payments-logger/backend/src/auth.js:103: authorization_servers: [HYDRA_PUBLIC_URL],
/volume2/docker/payments-logger/backend/src/auth.js:107: jwks_uri: `${HYDRA_PUBLIC_URL}/.well-known/jwks.json`,
/volume2/docker/payments-logger/backend/src/auth.js:111:wellKnownRouter.get('/.well-known/oauth-authorization-server', async (_req, res) => {
/volume2/docker/payments-logger/backend/src/auth.js:113: const r = await fetch(`${HYDRA_PUBLIC_URL}/.well-known/openid-configuration`);
/volume2/docker/payments-logger/backend/src/auth.js:118: issuer: doc.issuer || HYDRA_PUBLIC_URL,
Thinking
Thinking
payments-logger Authorization Overview
payments-logger Authorization Overview
The project uses
OAuth 2.1 with PKCE
via an external Hydra OAuth server at
hydra.lakylak.xyz
.
Auth Flow
Auth Flow
Frontend
(
frontend/src/auth.js
frontend/src/auth.js
):
Fetches OAuth server metadata via discovery endpoint
Generates a PKCE code verifier/challenge (SHA-256)
Redirects user to Hydra login with
code_challenge
On callback, exchanges code + verifier for tokens
Stores
access_token
,
refresh_token
in
localStorage
(
pl_oauth_tokens
)
Auto-refreshes token 30 seconds before expiry
Backend
(
backend/src/auth.js
backend/src/auth.js
):
bearerTokenMiddleware
validates the
Authorization: Bearer <token>
header
Fetches Hydra's JWKS (cached 300s) and verifies JWT signature (RS256/ES256/PS256)
Validates issuer (
https://hydra.lakylak.xyz
) and optional audience
Enforcement
Enforcement
Applied globally in
backend/src/index.js:19
backend/src/index.js:19
with these
public (unprotected) paths
:
/.well-known/oauth-protected-resource
/.well-known/oauth-authorization-server
/api/health
/api/payments/ingest
(rate-limited at 200 req/min — for SMS ingestion)
Roles/Permissions
Roles/Permissions
No RBAC
— it's binary: authenticated vs. unauthenticated. Required scopes:
openid
,
offline_access
.
Key Security Notes
Key Security Notes
PKCE
prevents authorization code interception
State parameter
provides CSRF protection
No server-side token storage
— validation is stateless via JWKS
The README/API docs mention an
X-API-Key
header, but that's
outdated
— the actual code uses Bearer tokens only
Config lives in
docker-compose.yml
docker-compose.yml
(lines 30–33):
HYDRA_PUBLIC_URL
,
REQUIRED_SCOPES
,
OAUTH_CLIENT_ID
, and optionally
TOKEN_AUDIENCE
/
JWKS_CACHE_TTL
.
Message actions
compare it to location logger and make it the same. Lets remove hydra and only use authentic (or whatever location logger uses).
Thinking
Thinking
Let me first explore how location-logger handles authorization.
Agent:
Explore location-logger authorization code
IN
Explore the location-logger project at /volume2/docker/location-logger and give me a thorough understanding of how authorization works. I need to know:
1. What auth mechanism is used (JWT, sessions, API keys, OAuth, etc.)
2. Where auth is enforced (middleware, decorators, route guards, etc.)
3. What roles/permissions exist
4. How tokens are issued, validated, and refreshed
5. Any auth-related config (env vars, settings)
6. Frontend auth flow (how the user logs in, how tokens are stored and used)
7. The full directory/file structure of the project
Please read ALL relevant source files completely and give me a detailed summary with file paths and line numbers. I need enough detail to replicate this auth system in another project.
Bash
IN
find /volume2/docker/location-logger -type f -name "*.py" -o -name "*.js" -o -name "*.ts" -o -name "*.json" | head -50
Copy code to clipboard
OUT
/volume2/docker/location-logger/.mcp.json
/volume2/docker/location-logger/app/__init__.py
/volume2/docker/location-logger/app/utils.py
/volume2/docker/location-logger/app/config.py
/volume2/docker/location-logger/app/main.py
/volume2/docker/location-logger/alembic/env.py
/volume2/docker/location-logger/mcp-server/server.py
/volume2/docker/location-logger/alembic/versions/20260203_201500_create_location_points_table.py
/volume2/docker/location-logger/alembic/versions/20260209_200000_add_enhanced_fields_and_tables.py
/volume2/docker/location-logger/alembic/versions/20260214_000000_add_users_and_audit_logs.py
/volume2/docker/location-logger/alembic/versions/20260320_000000_add_audit_query_string.py
/volume2/docker/location-logger/app/services/geofence_service.py
/volume2/docker/location-logger/app/services/recorder_service.py
/volume2/docker/location-logger/app/services/trip_service.py
/volume2/docker/location-logger/app/services/enhanced_location_service.py
/volume2/docker/location-logger/app/services/geocoding_service.py
/volume2/docker/location-logger/app/clients/__init__.py
/volume2/docker/location-logger/app/clients/dawarich_client.py
/volume2/docker/location-logger/app/clients/owntracks_client.py
/volume2/docker/location-logger/app/models/areas.py
/volume2/docker/location-logger/app/models/geofence_events.py
/volume2/docker/location-logger/app/models/trips.py
/volume2/docker/location-logger/app/models/user.py
/volume2/docker/location-logger/app/models/location.py
/volume2/docker/location-logger/app/models/audit_log.py
/volume2/docker/location-logger/app/auth/__init__.py
/volume2/docker/location-logger/app/auth/dependencies.py
/volume2/docker/location-logger/app/auth/utils.py
/volume2/docker/location-logger/app/api/enhanced_endpoints.py
/volume2/docker/location-logger/app/db/base.py
/volume2/docker/location-logger/app/db/session.py
Bash
IN
tree -L 4 /volume2/docker/location-logger 2>/dev/null || find /volume2/docker/location-logger -type d | sort
Copy code to clipboard
OUT
/volume2/docker/location-logger
├── alembic
│ ├── env.py
│ ├── script.py.mako
│ └── versions
│ ├── 20260203_201500_create_location_points_table.py
│ ├── 20260209_200000_add_enhanced_fields_and_tables.py
│ ├── 20260214_000000_add_users_and_audit_logs.py
│ ├── 20260320_000000_add_audit_query_string.py
│ └── __pycache__
│ └── 20260214_000000_add_users_and_audit_logs.cpython-311.pyc
├── alembic.ini
├── app
│ ├── api
│ │ └── enhanced_endpoints.py
│ ├── auth
│ │ ├── dependencies.py
│ │ ├── __init__.py
│ │ ├── __pycache__
│ │ │ ├── dependencies.cpython-311.pyc
│ │ │ ├── __init__.cpython-311.pyc
│ │ │ └── utils.cpython-311.pyc
│ │ └── utils.py
│ ├── clients
│ │ ├── dawarich_client.py
│ │ ├── __init__.py
│ │ └── owntracks_client.py
│ ├── config.py
│ ├── db
│ │ ├── base.py
│ │ └── session.py
│ ├── __init__.py
│ ├── main.py
│ ├── models
│ │ ├── areas.py
│ │ ├── audit_log.py
│ │ ├── geofence_events.py
│ │ ├── location.py
│ │ ├── __pycache__
│ │ │ ├── audit_log.cpython-311.pyc
│ │ │ └── user.cpython-311.pyc
│ │ ├── trips.py
│ │ └── user.py
│ ├── __pycache__
│ │ ├── __init__.cpython-311.pyc
│ │ └── main.cpython-311.pyc
│ ├── services
│ │ ├── enhanced_location_service.py
│ │ ├── geocoding_service.py
│ │ ├── geofence_service.py
│ │ ├── recorder_service.py
│ │ └── trip_service.py
│ ├── static
│ │ └── dashboard.html
│ └── utils.py
├── docker-compose.yml
├── Dockerfile
├── mcp-server
│ ├── Dockerfile
│ ├── requirements.txt
│ └── server.py
├── README.md
├── requirements.txt
└── today_map.html
16 directories, 48 files
Read
utils.py
utils.py
Read
dependencies.py
dependencies.py
Read
user.py
user.py
Read
config.py
config.py
Read
main.py
main.py
Read
session.py
session.py
Read
dashboard.html
dashboard.html
Read
audit_log.py
audit_log.py
Read
20260214_000000_add_users_and_audit_logs.py
20260214_000000_add_users_and_audit_logs.py
Read
20260320_000000_add_audit_query_string.py
20260320_000000_add_audit_query_string.py
Read
README.md
README.md
Read
requirements.txt
requirements.txt
Read
server.py
server.py
Read
server.py
server.py
(lines 101-400)
Thinking
Thinking
Now I have a full picture of both systems. Let me read the payments-logger source files before planning the migration.
Bash
List all payments-logger files
IN
find /volume2/docker/payments-logger -type f | grep -v node_modules | grep -v .git | sort
Copy code to clipboard
OUT
/volume2/docker/payments-logger/API.md
/volume2/docker/payments-logger/backend/Dockerfile
/volume2/docker/payments-logger/backend/.dockerignore
/volume2/docker/payments-logger/backend/package.json
/volume2/docker/payments-logger/backend/prisma/migrations/20260210_init/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260210_simplify/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260222_add_card/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml
/volume2/docker/payments-logger/backend/prisma/schema.prisma
/volume2/docker/payments-logger/backend/src/auth.js
/volume2/docker/payments-logger/backend/src/index.js
/volume2/docker/payments-logger/backend/src/parser.js
/volume2/docker/payments-logger/backend/src/routes/payments.js
/volume2/docker/payments-logger/.claude/settings.local.json
/volume2/docker/payments-logger/docker-compose.yml
/volume2/docker/payments-logger/.env
/volume2/docker/payments-logger/.env.example
/volume2/docker/payments-logger/frontend/Dockerfile
/volume2/docker/payments-logger/frontend/.dockerignore
/volume2/docker/payments-logger/frontend/index.html
/volume2/docker/payments-logger/frontend/package.json
/volume2/docker/payments-logger/frontend/postcss.config.js
/volume2/docker/payments-logger/frontend/src/App.jsx
/volume2/docker/payments-logger/frontend/src/auth.js
/volume2/docker/payments-logger/frontend/src/components/AuthCallback.jsx
/volume2/docker/payments-logger/frontend/src/components/AuthProvider.jsx
/volume2/docker/payments-logger/frontend/src/components/FilterBar.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentCard.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentList.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentTable.jsx
/volume2/docker/payments-logger/frontend/src/index.css
/volume2/docker/payments-logger/frontend/src/main.jsx
/volume2/docker/payments-logger/frontend/tailwind.config.js
/volume2/docker/payments-logger/frontend/vite.config.js
/volume2/docker/payments-logger/README.md
Read
auth.js
auth.js
Read
index.js
index.js
Read
auth.js
auth.js
Read
AuthProvider.jsx
AuthProvider.jsx
Read
package.json
package.json
Read
AuthCallback.jsx
AuthCallback.jsx
Read
schema.prisma
schema.prisma
Read
docker-compose.yml
docker-compose.yml
Thinking
Thinking
Now let me read the remaining frontend files.
Read
App.jsx
App.jsx
Read
package.json
package.json
Read
.env
.env
Thinking
Thinking
Let me read the remaining files before making changes.
Read
main.jsx
main.jsx
Read
vite.config.js
vite.config.js
Read
payments.js
payments.js
Thinking...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
11372
|
516
|
11
|
2026-05-08T19:13:57.630688+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778267637630_m2.jpg...
|
Firefox
|
Nginx Proxy Manager — Personal
|
True
|
http://192.168.0.242:81/nginx/proxy
|
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
Nginx Proxy Manager
Nginx Proxy Manager
Close tab
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
All docs · AFFiNE
All docs · AFFiNE
Payments Logger
Payments Logger
[NirDiamant/GenAI_Agents] Add SwarmScore — Portable Trust Rating for AI Agents (Issue #115) - [EMAIL] - Gmail
[NirDiamant/GenAI_Agents] Add SwarmScore — Portable Trust Rating for AI Agents (Issue #115) - [EMAIL] - Gmail
New Tab
New Tab
Location Logger
Location Logger
Finance Hub
Finance Hub
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Nginx Proxy Manager
Nginx Proxy Manager
Admin Administrator
Admin
Administrator
Dashboard
Dashboard
Hosts
Hosts
Access Lists
Access Lists
SSL Certificates
SSL Certificates
Users
Users
Audit Log
Audit Log
Settings
Settings
Proxy Hosts
Proxy Hosts
Search Host…
Add Proxy Host
Add Proxy Host
SOURCE
DESTINATION
SSL
ACCESS
STATUS
ai.chat.lakylak.xyz
Created: 10th March 2026
http://[IP_ADDRESS]:11000
Let's Encrypt
Public
Online
app.lakylak.xyz
Created: 19th July 2025
http://[IP_ADDRESS]:18083
Let's Encrypt
Public
Online
app.payments.lakylak.xyz
Created: 14th February 2026
http://[IP_ADDRESS]:5174
Let's Encrypt
Public
Online
app.screenpipe.lakylak.xyz
Created: 27th April 2026
http://[IP_ADDRESS]:8766
Let's Encrypt
Public
Online
audiobook.lakylak.xyz
Created: 15th June 2025
http://192.168..242:13378
Let's Encrypt
Public
Online
auth.lakylak.xyz
Created: 30th March 2026
http://[IP_ADDRESS]:9100
Let's Encrypt
Public
Online
backup.lakylak.xyz
Created: 10th July 2025
http://[IP_ADDRESS]:9999
Let's Encrypt
Public
Online
beszel.lakylak.xyz
Created: 6th December 2025
http://[IP_ADDRESS]:8095
Let's Encrypt
Public
Online
bitwarden.lakylak.xyz
Created: 16th June 2025
http://[IP_ADDRESS]:9890
Let's Encrypt
Public
Online
book.lakylak.xyz
Created: 31st October 2025
http://[IP_ADDRESS]:6060
Let's Encrypt
Public
Online
crm.lakylak.xyz
Created: 25th July 2025
http://[IP_ADDRESS]:3353
Let's Encrypt
Public
Online
dawarich.lakylak.xyz
Created: 25th August 2025
http://[IP_ADDRESS]:3000
Let's Encrypt
Public
Online
db.screenpipe.lakylak.xyz
Created: 27th April 2026
http://[IP_ADDRESS]:8767
Let's Encrypt
Public
Online
dsk-uploader.lakylak.xyz
Created: 15th August 2025
http://[IP_ADDRESS]:8502
Let's Encrypt
Public
Online
gitea.lakylak.xyz
Created: 18th July 2025
http://[IP_ADDRESS]:3052
Let's Encrypt
Public
Online
hydra.lakylak.xyz
Created: 29th March 2026
http://[IP_ADDRESS]:4444
Let's Encrypt
Public
Online
images.lakylak.xyz
Created: 17th June 2025
http://[IP_ADDRESS]:3474
Let's Encrypt
Public
Online
immich.lakylak.xyz
Created: 15th June 2025
http://[IP_ADDRESS]:8212
Let's Encrypt
Public
Online
jellyfin.lakylak.xyz
Created: 15th June 2025
http://[IP_ADDRESS]:8096
Let's Encrypt
Public
Online
lakylak.xyz
Created: 15th June 2025
http://[IP_ADDRESS]:9999
Let's Encrypt
Public
Online
linkwarden.lakylak.xyz
Created: 13th December 2025
http://[IP_ADDRESS]:7461
Let's Encrypt
Public
Online
location-tracker.lakylak.xyz
Created: 30th August 2025
http://[IP_ADDRESS]:8050
Let's Encrypt
Public
Online
log.lakylak.xyz
Created: 23rd September 2025
http://[IP_ADDRESS]:18084
Let's Encrypt
Public
Online
login.lakylak.xyz
Created: 29th March 2026
http://[IP_ADDRESS]:4446
Let's Encrypt
Public
Online
mcp.location.lakylak.xyz
Created: 15th March 2026
http://[IP_ADDRESS]:8052
Let's Encrypt
Public
Online
n8n.lakylak.xyz
Created: 17th July 2025
http://[IP_ADDRESS]:5678
Let's Encrypt
Public
Online
nas.lakylak.xyz
Created: 28th July 2025
http://[IP_ADDRESS]:9999
Let's Encrypt
Public
Online
notes.lakylak.xyz
Created: 31st October 2025
http://[IP_ADDRESS]:8085
Let's Encrypt
Public
Online
obsidian.lakylak.xyz
Created: 17th June 2025
http://[IP_ADDRESS]:3421
Let's Encrypt
Public
Online
outfit.lakylak.xyz
Created: 25th March 2026
http://[IP_ADDRESS]:8667
Let's Encrypt
Public
Online
owntracks.lakylak.xyz
Created: 12th August 2025
http://[IP_ADDRESS]:8083
Let's Encrypt
Public
Online
paperless.lakylak.xyz
Created: 25th October 2025
http://[IP_ADDRESS]:8777
Let's Encrypt
Public
Online
payments.lakylak.xyz
Created: 14th February 2026
http://[IP_ADDRESS]:3010
Let's Encrypt
Public
Online
pdf.lakylak.xyz
Created: 19th June 2025
http://[IP_ADDRESS]:7890
Let's Encrypt
Public
Online
portainer.lakylak.xyz
Created: 15th June 2025
http://[IP_ADDRESS]:9000
Let's Encrypt
Public
Online
sqlite.screenpipe.lakylak.xyz
Created: 27th April 2026
http://[IP_ADDRESS]:8768
Let's Encrypt
Public
Online
todo.lakylak.xyz
Created: 16th March 2026
http://reminder-app:8000
Let's Encrypt
Public
Online
tree.lakylak.xyz
Created: 19th December 2025
http://[IP_ADDRESS]:8200
Let's Encrypt
Public
Online
trilium.lakylak.xyz
Created: 24th December 2025
http://[IP_ADDRESS]:4292
Let's Encrypt
Public
Online
tube.lakylak.xyz
Created: 3rd December 2025
http://[IP_ADDRESS]:8770
Let's Encrypt
Public
Online
ytber.lakylak.xyz
Created: 11th March 2026
http://[IP_ADDRESS]:8100
Let's Encrypt
Public
Online
SOURCE
ai.chat.lakylak.xyz
Created: 10th March 2026
app.lakylak.xyz
Created: 19th July 2025
app.payments.lakylak.xyz
Created: 14th February 2026
app.screenpipe.lakylak.xyz
Created: 27th April 2026
audiobook.lakylak.xyz
Created: 15th June 2025
auth.lakylak.xyz
Created: 30th March 2026
backup.lakylak.xyz
Created: 10th July 2025
beszel.lakylak.xyz...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.0,"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.013297873,"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.0,"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.013297873,"top":0.09577015,"width":0.03025266,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Nginx Proxy Manager","depth":4,"bounds":{"left":0.0,"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":true},{"role":"AXStaticText","text":"Nginx Proxy Manager","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.10139628,"top":0.1245012,"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":"Screenpipe — Archive","depth":4,"bounds":{"left":0.0,"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.013297873,"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.0,"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.013297873,"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.0,"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.013297873,"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.0,"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.013297873,"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.0,"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.013297873,"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.0,"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.013297873,"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.0,"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":false},{"role":"AXStaticText","text":"AFFiNE - All In One KnowledgeOS","depth":5,"bounds":{"left":0.013297873,"top":0.3575419,"width":0.05851064,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"All docs · AFFiNE","depth":4,"bounds":{"left":0.0,"top":0.3790902,"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":"All docs · AFFiNE","depth":5,"bounds":{"left":0.013297873,"top":0.39026338,"width":0.029587766,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Payments Logger","depth":4,"bounds":{"left":0.0,"top":0.41181165,"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":"Payments Logger","depth":5,"bounds":{"left":0.013297873,"top":0.42298484,"width":0.030086435,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[NirDiamant/GenAI_Agents] Add SwarmScore — Portable Trust Rating for AI Agents (Issue #115) - kovaliklukas@gmail.com - Gmail","depth":4,"bounds":{"left":0.0,"top":0.4445331,"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":"[NirDiamant/GenAI_Agents] Add SwarmScore — Portable Trust Rating for AI Agents (Issue #115) - kovaliklukas@gmail.com - Gmail","depth":5,"bounds":{"left":0.013297873,"top":0.4557063,"width":0.22639628,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.0,"top":0.4772546,"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":"New Tab","depth":5,"bounds":{"left":0.013297873,"top":0.4884278,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Location Logger","depth":4,"bounds":{"left":0.0,"top":0.509976,"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":"Location Logger","depth":5,"bounds":{"left":0.013297873,"top":0.5211492,"width":0.028091755,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Finance Hub","depth":4,"bounds":{"left":0.0,"top":0.54269755,"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":"Finance Hub","depth":5,"bounds":{"left":0.013297873,"top":0.55387074,"width":0.021609042,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.57701516,"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.0028257978,"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.013796543,"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.024933511,"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.036070477,"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.04720745,"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":"Nginx Proxy Manager","depth":8,"bounds":{"left":0.1512633,"top":0.061452515,"width":0.06665558,"height":0.03471668},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Nginx Proxy Manager","depth":9,"bounds":{"left":0.1619016,"top":0.06783719,"width":0.056017287,"height":0.018355945},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Admin Administrator","depth":8,"bounds":{"left":0.42021278,"top":0.06584198,"width":0.042220745,"height":0.02593775},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Admin","depth":10,"bounds":{"left":0.4375,"top":0.06424581,"width":0.013464096,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Administrator","depth":11,"bounds":{"left":0.4375,"top":0.07980846,"width":0.024933511,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":" Dashboard","depth":10,"bounds":{"left":0.1512633,"top":0.10654429,"width":0.028756648,"height":0.044293694},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":12,"bounds":{"left":0.1512633,"top":0.122505985,"width":0.004654255,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dashboard","depth":11,"bounds":{"left":0.15724733,"top":0.12051077,"width":0.022772606,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":" Hosts","depth":10,"bounds":{"left":0.18799867,"top":0.10654429,"width":0.01761968,"height":0.044293694},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":12,"bounds":{"left":0.18799867,"top":0.122505985,"width":0.004654255,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Hosts","depth":11,"bounds":{"left":0.1939827,"top":0.12051077,"width":0.011635638,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":" Access Lists","depth":10,"bounds":{"left":0.21359707,"top":0.10654429,"width":0.030086435,"height":0.044293694},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":12,"bounds":{"left":0.21359707,"top":0.122505985,"width":0.004654255,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Access Lists","depth":11,"bounds":{"left":0.21958111,"top":0.12051077,"width":0.024102394,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":" SSL Certificates","depth":10,"bounds":{"left":0.25166222,"top":0.10654429,"width":0.038065158,"height":0.044293694},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":12,"bounds":{"left":0.25166222,"top":0.122505985,"width":0.004654255,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SSL Certificates","depth":11,"bounds":{"left":0.25764626,"top":0.12051077,"width":0.032081116,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":" Users","depth":10,"bounds":{"left":0.29770613,"top":0.10654429,"width":0.01761968,"height":0.044293694},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":12,"bounds":{"left":0.29770613,"top":0.122505985,"width":0.004654255,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Users","depth":11,"bounds":{"left":0.30369017,"top":0.12051077,"width":0.011635638,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":" Audit Log","depth":10,"bounds":{"left":0.32330453,"top":0.10654429,"width":0.025598405,"height":0.044293694},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":12,"bounds":{"left":0.32330453,"top":0.122505985,"width":0.004654255,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Audit Log","depth":11,"bounds":{"left":0.32928857,"top":0.12051077,"width":0.019614361,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":" Settings","depth":10,"bounds":{"left":0.35688165,"top":0.10654429,"width":0.022938829,"height":0.044293694},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":12,"bounds":{"left":0.35688165,"top":0.122505985,"width":0.004654255,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Settings","depth":11,"bounds":{"left":0.3628657,"top":0.12051077,"width":0.016954787,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Proxy Hosts","depth":9,"bounds":{"left":0.15957446,"top":0.1839585,"width":0.02925532,"height":0.017557861},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Proxy Hosts","depth":10,"bounds":{"left":0.15957446,"top":0.18355946,"width":0.02925532,"height":0.018355945},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"","depth":11,"bounds":{"left":0.3409242,"top":0.1867518,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Search Host…","depth":10,"bounds":{"left":0.33676863,"top":0.18156424,"width":0.06898271,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"","depth":9,"bounds":{"left":0.4084109,"top":0.18156424,"width":0.011303191,"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":"","depth":10,"bounds":{"left":0.4114029,"top":0.1867518,"width":0.005319149,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Add Proxy Host","depth":9,"bounds":{"left":0.42237368,"top":0.18156424,"width":0.034408245,"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":"Add Proxy Host","depth":10,"bounds":{"left":0.4253657,"top":0.1859537,"width":0.028424202,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SOURCE","depth":12,"bounds":{"left":0.17819148,"top":0.22306465,"width":0.016289894,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DESTINATION","depth":12,"bounds":{"left":0.25748006,"top":0.22306465,"width":0.02642952,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SSL","depth":12,"bounds":{"left":0.33743352,"top":0.22306465,"width":0.0071476065,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ACCESS","depth":12,"bounds":{"left":0.38131648,"top":0.22306465,"width":0.01512633,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"STATUS","depth":12,"bounds":{"left":0.41023937,"top":0.22306465,"width":0.014960106,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ai.chat.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.25897846,"width":0.030418882,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 10th March 2026","depth":13,"bounds":{"left":0.17819148,"top":0.28052673,"width":0.046043884,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:11000","depth":13,"bounds":{"left":0.25748006,"top":0.26735833,"width":0.055518616,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.33743352,"top":0.26735833,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.38131648,"top":0.26735833,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.41489363,"top":0.26735833,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.44913563,"top":0.26735833,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.44913563,"top":0.26855546,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.31843576,"width":0.025598405,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 19th July 2025","depth":13,"bounds":{"left":0.17819148,"top":0.33998403,"width":0.042386968,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:18083","depth":13,"bounds":{"left":0.25748006,"top":0.3272147,"width":0.055518616,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.33743352,"top":0.3272147,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.38131648,"top":0.3272147,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.41489363,"top":0.3272147,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.44913563,"top":0.3272147,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.44913563,"top":0.32841182,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app.payments.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.37789306,"width":0.04305186,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 14th February 2026","depth":13,"bounds":{"left":0.17819148,"top":0.39944133,"width":0.05119681,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:5174","depth":13,"bounds":{"left":0.25748006,"top":0.386672,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.33743352,"top":0.386672,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.38131648,"top":0.386672,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.41489363,"top":0.386672,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.44913563,"top":0.386672,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.44913563,"top":0.38786912,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app.screenpipe.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.43774942,"width":0.04488032,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 27th April 2026","depth":13,"bounds":{"left":0.17819148,"top":0.4592977,"width":0.04338431,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8766","depth":13,"bounds":{"left":0.25748006,"top":0.4461293,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.33743352,"top":0.4461293,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.38131648,"top":0.4461293,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.41489363,"top":0.4461293,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.44913563,"top":0.4461293,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.44913563,"top":0.44732642,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"audiobook.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.49720672,"width":0.03723404,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 15th June 2025","depth":13,"bounds":{"left":0.17819148,"top":0.51875496,"width":0.043882977,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168..242:13378","depth":13,"bounds":{"left":0.25748006,"top":0.5059856,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.33743352,"top":0.5059856,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.38131648,"top":0.5059856,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.41489363,"top":0.5059856,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.44913563,"top":0.5059856,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.44913563,"top":0.5071828,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"auth.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.556664,"width":0.026928192,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 30th March 2026","depth":13,"bounds":{"left":0.17819148,"top":0.5786113,"width":0.046043884,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:9100","depth":13,"bounds":{"left":0.25748006,"top":0.5654429,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.33743352,"top":0.5654429,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.38131648,"top":0.5654429,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.41489363,"top":0.5654429,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.44913563,"top":0.5654429,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.44913563,"top":0.5666401,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"backup.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.61652035,"width":0.031416222,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 10th July 2025","depth":13,"bounds":{"left":0.17819148,"top":0.6380686,"width":0.042386968,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.243:9999","depth":13,"bounds":{"left":0.25748006,"top":0.6249002,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.33743352,"top":0.6249002,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.38131648,"top":0.6249002,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.41489363,"top":0.6249002,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.44913563,"top":0.6249002,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.44913563,"top":0.6260974,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"beszel.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.67597765,"width":0.029587766,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 6th December 2025","depth":13,"bounds":{"left":0.17819148,"top":0.6975259,"width":0.05119681,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8095","depth":13,"bounds":{"left":0.25748006,"top":0.6847566,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.33743352,"top":0.6847566,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.38131648,"top":0.6847566,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.41489363,"top":0.6847566,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.44913563,"top":0.6847566,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.44913563,"top":0.68595374,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"bitwarden.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.73543495,"width":0.036236703,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 16th June 2025","depth":13,"bounds":{"left":0.17819148,"top":0.7573823,"width":0.043882977,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:9890","depth":13,"bounds":{"left":0.25748006,"top":0.7442139,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.33743352,"top":0.7442139,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.38131648,"top":0.7442139,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.41489363,"top":0.7442139,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.44913563,"top":0.7442139,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.44913563,"top":0.74541104,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"book.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.7952913,"width":0.027759308,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 31st October 2025","depth":13,"bounds":{"left":0.17819148,"top":0.8168396,"width":0.04886968,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:6060","depth":13,"bounds":{"left":0.25748006,"top":0.8036712,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.33743352,"top":0.8036712,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.38131648,"top":0.8036712,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.41489363,"top":0.8036712,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.44913563,"top":0.8036712,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.44913563,"top":0.80486834,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"crm.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.8547486,"width":0.025598405,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 25th July 2025","depth":13,"bounds":{"left":0.17819148,"top":0.8762969,"width":0.042386968,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:3353","depth":13,"bounds":{"left":0.25748006,"top":0.86352754,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.33743352,"top":0.86352754,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.38131648,"top":0.86352754,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.41489363,"top":0.86352754,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.44913563,"top":0.86352754,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.44913563,"top":0.86472464,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dawarich.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.91460496,"width":0.034574468,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 25th August 2025","depth":13,"bounds":{"left":0.17819148,"top":0.93615323,"width":0.04737367,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:3000","depth":13,"bounds":{"left":0.25748006,"top":0.92298484,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.33743352,"top":0.92298484,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.38131648,"top":0.92298484,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.41489363,"top":0.92298484,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.44913563,"top":0.92298484,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.44913563,"top":0.92418194,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"db.screenpipe.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.97406226,"width":0.04288564,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 27th April 2026","depth":13,"bounds":{"left":0.17819148,"top":0.99561054,"width":0.04338431,"height":0.004389465},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8767","depth":13,"bounds":{"left":0.25748006,"top":0.9828412,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.33743352,"top":0.9828412,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.38131648,"top":0.9828412,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.41489363,"top":0.9828412,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.44913563,"top":0.9828412,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.44913563,"top":0.9840383,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dsk-uploader.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":1.0,"width":0.04089096,"height":-0.033519506},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 15th August 2025","depth":13,"bounds":{"left":0.17819148,"top":1.0,"width":0.04737367,"height":-0.055067778},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8502","depth":13,"bounds":{"left":0.25748006,"top":1.0,"width":0.053025264,"height":-0.042298436},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.33743352,"top":1.0,"width":0.026928192,"height":-0.042298436},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.38131648,"top":1.0,"width":0.013131649,"height":-0.042298436},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.41489363,"top":1.0,"width":0.014793883,"height":-0.042298436},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.44913563,"top":1.0,"width":0.004986702,"height":-0.042298436},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.44913563,"top":1.0,"width":0.004986702,"height":-0.043495655},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"gitea.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":1.0,"width":0.027426861,"height":-0.09337592},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 18th July 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:3052","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"hydra.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 29th March 2026","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:4444","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"images.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 17th June 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:3474","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"immich.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 15th June 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8212","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"jellyfin.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 15th June 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8096","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 15th June 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:9999","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"linkwarden.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 13th December 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:7461","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"location-tracker.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 30th August 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8050","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"log.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 23rd September 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:18084","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"login.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 29th March 2026","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:4446","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mcp.location.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 15th March 2026","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8052","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"n8n.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 17th July 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:5678","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"nas.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 28th July 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:9999","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"notes.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 31st October 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8085","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"obsidian.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 17th June 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:3421","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"outfit.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 25th March 2026","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8667","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"owntracks.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 12th August 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8083","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"paperless.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 25th October 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8777","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"payments.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 14th February 2026","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:3010","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"pdf.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 19th June 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:7890","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"portainer.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 15th June 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:9000","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"sqlite.screenpipe.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 27th April 2026","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8768","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"todo.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 16th March 2026","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://reminder-app:8000","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"tree.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 19th December 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8200","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"trilium.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 24th December 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:4292","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"tube.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 3rd December 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8770","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ytber.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 11th March 2026","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8100","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SOURCE","depth":12,"bounds":{"left":0.17819148,"top":0.22306465,"width":0.016289894,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ai.chat.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.25897846,"width":0.030418882,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 10th March 2026","depth":13,"bounds":{"left":0.17819148,"top":0.28052673,"width":0.046043884,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.31843576,"width":0.025598405,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 19th July 2025","depth":13,"bounds":{"left":0.17819148,"top":0.33998403,"width":0.042386968,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app.payments.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.37789306,"width":0.04305186,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 14th February 2026","depth":13,"bounds":{"left":0.17819148,"top":0.39944133,"width":0.05119681,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app.screenpipe.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.43774942,"width":0.04488032,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 27th April 2026","depth":13,"bounds":{"left":0.17819148,"top":0.4592977,"width":0.04338431,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"audiobook.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.49720672,"width":0.03723404,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 15th June 2025","depth":13,"bounds":{"left":0.17819148,"top":0.51875496,"width":0.043882977,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"auth.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.556664,"width":0.026928192,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 30th March 2026","depth":13,"bounds":{"left":0.17819148,"top":0.5786113,"width":0.046043884,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"backup.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.61652035,"width":0.031416222,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 10th July 2025","depth":13,"bounds":{"left":0.17819148,"top":0.6380686,"width":0.042386968,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"beszel.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.67597765,"width":0.029587766,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-8080313991208056009
|
-7237535241734934209
|
click
|
accessibility
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Home | Hostinger
Home | Hostinger
Nginx Proxy Manager
Nginx Proxy Manager
Close tab
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
All docs · AFFiNE
All docs · AFFiNE
Payments Logger
Payments Logger
[NirDiamant/GenAI_Agents] Add SwarmScore — Portable Trust Rating for AI Agents (Issue #115) - [EMAIL] - Gmail
[NirDiamant/GenAI_Agents] Add SwarmScore — Portable Trust Rating for AI Agents (Issue #115) - [EMAIL] - Gmail
New Tab
New Tab
Location Logger
Location Logger
Finance Hub
Finance Hub
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Nginx Proxy Manager
Nginx Proxy Manager
Admin Administrator
Admin
Administrator
Dashboard
Dashboard
Hosts
Hosts
Access Lists
Access Lists
SSL Certificates
SSL Certificates
Users
Users
Audit Log
Audit Log
Settings
Settings
Proxy Hosts
Proxy Hosts
Search Host…
Add Proxy Host
Add Proxy Host
SOURCE
DESTINATION
SSL
ACCESS
STATUS
ai.chat.lakylak.xyz
Created: 10th March 2026
http://[IP_ADDRESS]:11000
Let's Encrypt
Public
Online
app.lakylak.xyz
Created: 19th July 2025
http://[IP_ADDRESS]:18083
Let's Encrypt
Public
Online
app.payments.lakylak.xyz
Created: 14th February 2026
http://[IP_ADDRESS]:5174
Let's Encrypt
Public
Online
app.screenpipe.lakylak.xyz
Created: 27th April 2026
http://[IP_ADDRESS]:8766
Let's Encrypt
Public
Online
audiobook.lakylak.xyz
Created: 15th June 2025
http://192.168..242:13378
Let's Encrypt
Public
Online
auth.lakylak.xyz
Created: 30th March 2026
http://[IP_ADDRESS]:9100
Let's Encrypt
Public
Online
backup.lakylak.xyz
Created: 10th July 2025
http://[IP_ADDRESS]:9999
Let's Encrypt
Public
Online
beszel.lakylak.xyz
Created: 6th December 2025
http://[IP_ADDRESS]:8095
Let's Encrypt
Public
Online
bitwarden.lakylak.xyz
Created: 16th June 2025
http://[IP_ADDRESS]:9890
Let's Encrypt
Public
Online
book.lakylak.xyz
Created: 31st October 2025
http://[IP_ADDRESS]:6060
Let's Encrypt
Public
Online
crm.lakylak.xyz
Created: 25th July 2025
http://[IP_ADDRESS]:3353
Let's Encrypt
Public
Online
dawarich.lakylak.xyz
Created: 25th August 2025
http://[IP_ADDRESS]:3000
Let's Encrypt
Public
Online
db.screenpipe.lakylak.xyz
Created: 27th April 2026
http://[IP_ADDRESS]:8767
Let's Encrypt
Public
Online
dsk-uploader.lakylak.xyz
Created: 15th August 2025
http://[IP_ADDRESS]:8502
Let's Encrypt
Public
Online
gitea.lakylak.xyz
Created: 18th July 2025
http://[IP_ADDRESS]:3052
Let's Encrypt
Public
Online
hydra.lakylak.xyz
Created: 29th March 2026
http://[IP_ADDRESS]:4444
Let's Encrypt
Public
Online
images.lakylak.xyz
Created: 17th June 2025
http://[IP_ADDRESS]:3474
Let's Encrypt
Public
Online
immich.lakylak.xyz
Created: 15th June 2025
http://[IP_ADDRESS]:8212
Let's Encrypt
Public
Online
jellyfin.lakylak.xyz
Created: 15th June 2025
http://[IP_ADDRESS]:8096
Let's Encrypt
Public
Online
lakylak.xyz
Created: 15th June 2025
http://[IP_ADDRESS]:9999
Let's Encrypt
Public
Online
linkwarden.lakylak.xyz
Created: 13th December 2025
http://[IP_ADDRESS]:7461
Let's Encrypt
Public
Online
location-tracker.lakylak.xyz
Created: 30th August 2025
http://[IP_ADDRESS]:8050
Let's Encrypt
Public
Online
log.lakylak.xyz
Created: 23rd September 2025
http://[IP_ADDRESS]:18084
Let's Encrypt
Public
Online
login.lakylak.xyz
Created: 29th March 2026
http://[IP_ADDRESS]:4446
Let's Encrypt
Public
Online
mcp.location.lakylak.xyz
Created: 15th March 2026
http://[IP_ADDRESS]:8052
Let's Encrypt
Public
Online
n8n.lakylak.xyz
Created: 17th July 2025
http://[IP_ADDRESS]:5678
Let's Encrypt
Public
Online
nas.lakylak.xyz
Created: 28th July 2025
http://[IP_ADDRESS]:9999
Let's Encrypt
Public
Online
notes.lakylak.xyz
Created: 31st October 2025
http://[IP_ADDRESS]:8085
Let's Encrypt
Public
Online
obsidian.lakylak.xyz
Created: 17th June 2025
http://[IP_ADDRESS]:3421
Let's Encrypt
Public
Online
outfit.lakylak.xyz
Created: 25th March 2026
http://[IP_ADDRESS]:8667
Let's Encrypt
Public
Online
owntracks.lakylak.xyz
Created: 12th August 2025
http://[IP_ADDRESS]:8083
Let's Encrypt
Public
Online
paperless.lakylak.xyz
Created: 25th October 2025
http://[IP_ADDRESS]:8777
Let's Encrypt
Public
Online
payments.lakylak.xyz
Created: 14th February 2026
http://[IP_ADDRESS]:3010
Let's Encrypt
Public
Online
pdf.lakylak.xyz
Created: 19th June 2025
http://[IP_ADDRESS]:7890
Let's Encrypt
Public
Online
portainer.lakylak.xyz
Created: 15th June 2025
http://[IP_ADDRESS]:9000
Let's Encrypt
Public
Online
sqlite.screenpipe.lakylak.xyz
Created: 27th April 2026
http://[IP_ADDRESS]:8768
Let's Encrypt
Public
Online
todo.lakylak.xyz
Created: 16th March 2026
http://reminder-app:8000
Let's Encrypt
Public
Online
tree.lakylak.xyz
Created: 19th December 2025
http://[IP_ADDRESS]:8200
Let's Encrypt
Public
Online
trilium.lakylak.xyz
Created: 24th December 2025
http://[IP_ADDRESS]:4292
Let's Encrypt
Public
Online
tube.lakylak.xyz
Created: 3rd December 2025
http://[IP_ADDRESS]:8770
Let's Encrypt
Public
Online
ytber.lakylak.xyz
Created: 11th March 2026
http://[IP_ADDRESS]:8100
Let's Encrypt
Public
Online
SOURCE
ai.chat.lakylak.xyz
Created: 10th March 2026
app.lakylak.xyz
Created: 19th July 2025
app.payments.lakylak.xyz
Created: 14th February 2026
app.screenpipe.lakylak.xyz
Created: 27th April 2026
audiobook.lakylak.xyz
Created: 15th June 2025
auth.lakylak.xyz
Created: 30th March 2026
backup.lakylak.xyz
Created: 10th July 2025
beszel.lakylak.xyz...
|
11368
|
NULL
|
NULL
|
NULL
|
|
6810
|
298
|
2
|
2026-05-08T07:18:14.162418+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778224694162_m2.jpg...
|
Slack
|
support (Channel) - Jiminny Inc - 5 new items - Sl support (Channel) - Jiminny Inc - 5 new items - Slack...
|
True
|
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
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Stefka Stoyanova
Ves
Galya Dimitrova
Aneliya Angelova
Vasil Vasilev
James Graham
Nikolay Ivanov
Lukas Kovalik
you...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.0056515955,"top":0.058260176,"width":0.011968086,"height":0.028731046},"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.0029920214,"top":0.10055866,"width":0.017287234,"height":0.054269753},"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.0066489363,"top":0.13806863,"width":0.009973404,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.0029920214,"top":0.15482841,"width":0.017287234,"height":0.054269753},"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.0076462766,"top":0.19233839,"width":0.007978723,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.0029920214,"top":0.20909816,"width":0.017287234,"height":0.054269753},"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.004986702,"top":0.24660814,"width":0.012965426,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.005319149,"top":0.24660814,"width":0.0026595744,"height":0.011173184}},{"char_start":1,"char_count":7,"bounds":{"left":0.0076462766,"top":0.24660814,"width":0.010638298,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.0029920214,"top":0.26336792,"width":0.017287234,"height":0.054269753},"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.0076462766,"top":0.3008779,"width":0.0076462766,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.007978723,"top":0.3008779,"width":0.0019946808,"height":0.011173184}},{"char_start":1,"char_count":4,"bounds":{"left":0.009973404,"top":0.3008779,"width":0.0056515955,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.0029920214,"top":0.31763768,"width":0.017287234,"height":0.054269753},"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.00731383,"top":0.35514766,"width":0.008643617,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.00731383,"top":0.35514766,"width":0.0019946808,"height":0.011173184}},{"char_start":1,"char_count":4,"bounds":{"left":0.00930851,"top":0.35514766,"width":0.0066489363,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.0029920214,"top":0.3719074,"width":0.017287234,"height":0.054269753},"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.006981383,"top":0.4094174,"width":0.008976064,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.00731383,"top":0.4094174,"width":0.0033244682,"height":0.011173184}},{"char_start":1,"char_count":3,"bounds":{"left":0.010638298,"top":0.4094174,"width":0.0056515955,"height":0.011173184}}],"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.042220745,"top":0.09177973,"width":0.027593086,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.042220745,"top":0.10055866,"width":0.025598405,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.10055866,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":10,"bounds":{"left":0.04488032,"top":0.10055866,"width":0.022938829,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.042220745,"top":0.12290503,"width":0.015957447,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.12290503,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.04488032,"top":0.12290503,"width":0.013297873,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"bounds":{"left":0.042220745,"top":0.1452514,"width":0.022938829,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.1452514,"width":0.0013297872,"height":0.014365523}},{"char_start":1,"char_count":9,"bounds":{"left":0.043550532,"top":0.1452514,"width":0.021609042,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"bounds":{"left":0.042220745,"top":0.16759777,"width":0.034906916,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.16759777,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.045212764,"top":0.16759777,"width":0.031914894,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"bounds":{"left":0.042220745,"top":0.18994413,"width":0.03856383,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.18994413,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.045212764,"top":0.18994413,"width":0.03557181,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"bounds":{"left":0.042220745,"top":0.2122905,"width":0.01662234,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.2122905,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":5,"bounds":{"left":0.044215426,"top":0.2122905,"width":0.014960106,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"bounds":{"left":0.042220745,"top":0.23463687,"width":0.018284574,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.23463687,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":7,"bounds":{"left":0.044215426,"top":0.23463687,"width":0.016289894,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"bounds":{"left":0.042220745,"top":0.25698325,"width":0.024268618,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.25698325,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":11,"bounds":{"left":0.04454787,"top":0.25698325,"width":0.021941489,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"bounds":{"left":0.042220745,"top":0.2793296,"width":0.016954787,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.2793296,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.04454787,"top":0.2793296,"width":0.01462766,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"bounds":{"left":0.042220745,"top":0.30167598,"width":0.024268618,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.30167598,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":9,"bounds":{"left":0.044215426,"top":0.30167598,"width":0.022606382,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"bounds":{"left":0.042220745,"top":0.32402235,"width":0.04488032,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.32402235,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":20,"bounds":{"left":0.044215426,"top":0.32402235,"width":0.04720745,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.042220745,"top":0.37669593,"width":0.03756649,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.37669593,"width":0.0033244682,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.045545213,"top":0.37669593,"width":0.034242023,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"bounds":{"left":0.07945479,"top":0.37669593,"width":0.0063164895,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"bounds":{"left":0.08211436,"top":0.37669593,"width":0.014295213,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.08211436,"top":0.37669593,"width":0.0039893617,"height":0.014365523}},{"char_start":1,"char_count":13,"bounds":{"left":0.08610372,"top":0.37669593,"width":0.028922873,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"bounds":{"left":0.09607713,"top":0.3942538,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"bounds":{"left":0.09607713,"top":0.3942538,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.11735372,"top":0.37669593,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":16,"bounds":{"left":0.1200133,"top":0.37669593,"width":0.03557181,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"bounds":{"left":0.042220745,"top":0.3990423,"width":0.028922873,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.3990423,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":11,"bounds":{"left":0.04488032,"top":0.3990423,"width":0.026263298,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"bounds":{"left":0.042220745,"top":0.42138866,"width":0.03756649,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.42138866,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.04488032,"top":0.42138866,"width":0.03523936,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Ves","depth":23,"bounds":{"left":0.042220745,"top":0.44373503,"width":0.0076462766,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.44373503,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":2,"bounds":{"left":0.045212764,"top":0.44373503,"width":0.004986702,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"bounds":{"left":0.042220745,"top":0.4660814,"width":0.034906916,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.4660814,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":14,"bounds":{"left":0.045877658,"top":0.4660814,"width":0.03158245,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.042220745,"top":0.4884278,"width":0.03756649,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.4884278,"width":0.0033244682,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.045545213,"top":0.4884278,"width":0.034242023,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.042220745,"top":0.51077414,"width":0.026263298,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.51077414,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":12,"bounds":{"left":0.045212764,"top":0.51077414,"width":0.023271276,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"bounds":{"left":0.042220745,"top":0.5331205,"width":0.031914894,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.5331205,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":11,"bounds":{"left":0.044215426,"top":0.5331205,"width":0.029920213,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"bounds":{"left":0.042220745,"top":0.5554669,"width":0.031914894,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.5554669,"width":0.0039893617,"height":0.014365523}},{"char_start":1,"char_count":13,"bounds":{"left":0.046210106,"top":0.5554669,"width":0.027925532,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.042220745,"top":0.57781327,"width":0.02925532,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.57781327,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":12,"bounds":{"left":0.04488032,"top":0.57781327,"width":0.026928192,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"bounds":{"left":0.07413564,"top":0.57781327,"width":0.0063164895,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.07446808,"top":0.57781327,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":2,"bounds":{"left":0.07679521,"top":0.57781327,"width":0.0056515955,"height":0.014365523}}],"role_description":"text"}]...
|
-8078390211943394644
|
-1207583818697269585
|
app_switch
|
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
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Stefka Stoyanova
Ves
Galya Dimitrova
Aneliya Angelova
Vasil Vasilev
James Graham
Nikolay Ivanov
Lukas Kovalik
you
ActivityMoreSlackcalVIewJiminny... ~# engineering# general# jiminny-bg# platform-tickets# product launches# random# releases# soha-ofhce# support# thank-vous# the people of jimi..ó- Direct messages3 Aneliya Angelova. ...8 Stovan Tanev €Stefka Stoyanovafal Ves% Galya Dimitrova DAneliva Angelovaa Vasil Vasilev¿ James Grahame. Nikolay IvanovLukas Kovalik y...#:Apps& ToastJira Cloud> M.Jobsi• ProspectSearchStr.v ServiceTraitsTSyternalManstirat internal Account? LavoutTrait nhnT. NotSunnortedTr. SvncCrmEntitiec?. SvncCrmSieldsTT CuneCrmMotadeT SystemStateTra© DataClient.php© DecorateActivity.phmistonWindowHelp@ Describe what you are looking for# support8 33Messagese Files• BookmarksMore1 reply 9 days agoLauren Hudson 6:17 PMHello, reauest from Norstella to uodatetheir Jiminny to match this sharedsoreadsheet. Is somebody from the supportream ahle to hen nlease?Commercial Roster - 2026(C...E% 3 replies Last reply 3 days agoWednesday. May othvLauren Hudson 6:03 PMHello, can somehody loon me into theconversaton around Dingus & 7azzv(Enoch's) reauest for us to providetranscrints viden for them ahead of themleaving? Thank youOEA l 12 replies Last reply 23.Message #support+ Aaljectbetach.ong© MatchActivityCrmData.php(©) CrmActivityService.phgentonpx© CheckAndRetryRemoteMatch.php© JiminnyDebugCommand.php© HandleHubspotRateLimit.phpuHubsporclientinterace.png© PaginationState.phgPaginationeontig.ongmportbatchJob Irait.pngc) synchubspotobiecis.ongeCrmMatcherJob.phpC) MatchCrmData.php© Activity.phcviceDecorator.php0 Servicelntertace.phpents Hubspotc ientinterface42 A69 X2 Ahllable SapiCall)lakeRequest (Sthis->confia)) {Lmarer-›requestavarlablein(schis->contzq):pot] Rate limit exceeded, deferring request', [:->conf10->team_1d.l:->confia->getIdo.Lon (Limit reached for confiauration 1 Sthis->confio->oetIdolPequesttnunt (Sthic->confia)•imit(Se)) {SretryAfter = $this->parseRetryAfter($e):Sthis->loq->warning('[Hubspot] Received 429 from API'. ['team id''config id'= Sthis->conf10->team_1d)=> Sthis->config->qetIdo."retry after' => Sretrvafter.= Se->qetMessageolthrow new RateLimitExcention( message: 'Hubspot returned 429' SretrvAfter. Se)•throw $e;suppont Dally • In 4h 42 m100% 12Fri 8 May 10:18:14+0 ..© ProviderRateLimiter.php X = custom.logElaravel.log4 SF jiminny@localhost]A HS_local [jiminny@localhost]tiò accounts fimA console (PROD]# console [eu)A console [STAGING]use...class Providerratelimitenorotected RateLimiter SrateLimiter:public function __construct(RateLimiter $rateLimiter)(...}public function canMakeRequest(RateLimited $provider): bool/** Ovar RateLimitInterface $rateLimit */foreach (Sprovider->getRateLimits as $rateLimit) ‹$key = SrateLimit->getKeyO;if (Sthis->rateLimiter->tooManyAttempts($key, SrateLimit->getQuotaO)) ‹return truepubLic tunction requestava1lableln kateLimited Sprovider: 1ntreturn Sprovider->getRateLimits@->isNotEmptv@Sproviden->getRateLimits@(RateLimitInterface SrateLimit): int => Sthis->rateLimiter->availableIn(SrateLir->maxonublic function incrementReauestCountRateLimited Soroviden): void** Avan Ratel imitIntenface Sratelimit *^foreach (Sprovider->getRateLimits as $rateLimit){Sthicesnamit-›getKey, $rateLimit->getWindow0):in /vecterdav 10-2CascadeHubspot Rate LimitingHubspot Rate Limit HNow l have the comolete picture. Let me aive vou a precise walkthrouah.Part 1: Why 1300 Activities → 2600 Jobs (Step-by-Step)Step 1: One Delete Job Loops Through ActivitiesDeleteCrmEntityTrait.php:43-76a phosactivitles→>each tunction Activity Sactivity use ...// For 1300 activities, thisruns 1o00eamesSactivity→>update(l'account 1d = nulu);Sdispatcher->dispatch(new DetachActivity0bject(Sactivity, Scrmobject)); 11 ~ 1300 eventsResult after Steo 1: 1300 DetachAct ivitvObiect events fired one per activitv).Sten 2: Listener Reacts to Bach EventRematchAct1v1ty0nCrm0bjectDetach.php:/6-86tphoBus:: chainnew MatchActivityCrmData(activityId: ..., remoteSearch: false),new CheckAndRetryRemoteMatch(activityId->dispatcho:I/ Job Al// Job BFor each of the 1300 events, the listener dispatches a chain of 2 jobs.Result after Step 2:• 1300 x MatchActivityCrmData (local search. remoteSearch=false)Ston 2. ChockAndPotrvDemoteMntch Mav Dicnatch AnothorCheckAndRetryRemoteMatch.php: 46-86a phoit (ShasMatch) "return. // No new ioh if local match cucceededSdispatcher->dispatch(new MatchActivityCrmData(activityId: ..., remoteSearch: true)):If local search fails (most common after a delete), this dispatches a third MatchActivityCrmData (with remoteSearch=true )Step 4: Final Job CountsJob TvoeHits HubSoot Search API?• You've used 98% of your quota. Quota resets May 8, 11:00 AM GMT+3Reiect allAccent alliAsk anvthina (&4D)Claude Onus 4.7 Medium81-22fo 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
22291
|
968
|
17
|
2026-05-12T06:59:58.195860+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-12/1778 /Users/lukas/.screenpipe/data/data/2026-05-12/1778569198195_m1.jpg...
|
Firefox
|
LLM API Pricing Comparison & Cost Guide (May 2 LLM API Pricing Comparison & Cost Guide (May 2026) — Work...
|
True
|
costgoat.com/compare/llm-api
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
New Tab
New Tab
Jy 20820 es reindex stream model h New Tab
New Tab
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Pull requests · jiminny/app
Pull requests · jiminny/app
[JY-20773] User Pilot not receiving events on report generated - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
JY-20361: Add call scores in Panorama by steliyan-g · Pull Request #507 · jiminny/prophet
JY-20361: Add call scores in Panorama by steliyan-g · Pull Request #507 · jiminny/prophet
LLM API Pricing Comparison & Cost Guide (May 2026)
LLM API Pricing Comparison & Cost Guide (May 2026)
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Copy prompt
You said I’m on page “<tabTitle>JY-20361: Add call scores in Panorama by steliyan-</tabTitle>” with “<selection>@@ -4,7 +4,7 @@ Today is {date_today}.445System instructions:5System instructions:6- You must answer using markdown. Do not use html tags in your response even if requested by the user's question.6- You must answer using markdown. Do not use html tags in your response even if requested by the user's question.7-- The contexts includes data for call shortlisted through user-applied filters. Note that the calls might not relate to the same deal or not even be by the same sales rep.7+- The context includes data for calls shortlisted through user-applied filters. Note that the calls might not relate to the same deal or not even be by the same sales rep.8 - The full call context includes all calls data available while the short call context contains only an overview of the calls that are analysed. Refer to the short call context for quick reference and to see the overall picture.8 - The full call context includes all calls data available while the short call context contains only an overview of the calls that are analysed. Refer to the short call context for quick reference and to see the overall picture.9- The calls are ordered in chronological order. 9- The calls are ordered in chronological order. 10- Here’s how to use the call context:10- Here’s how to use the call context:@@ -16,6 +16,15 @@ System instructions:16 - Frame answers with awareness of the company’s ICP, deal cycle, and sales motion.16 - Frame answers with awareness of the company’s ICP, deal cycle, and sales motion.17 - Evaluate statements or objections based on how the team operates and what success looks like.17 - Evaluate statements or objections based on how the team operates and what success looks like.18 - Position responses in light of known competitors and market dynamics.18 - Position responses in light of known competitors and market dynamics.19+ - AI call score (`ai_call_score` in the full call JSON): When present, treat it as **pre-computed** output from your team’s AI call-scoring pipeline (the same kind of scoring as the `/call/ai-call-scoring` endpoint). **Do not** invent, override, or recalculate scores; interpret and summarize what is given.20+ - **Short call context:** **AI Scorecard** is the name of the scorecard applied to that call; **AI Score** is the **overall** score for that scorecard (the average of its per-rule scores, possibly shown as a decimal).21+ - **Full call context:** The `ai_call_score` object may include `ai_scorecard_name`, `score` (overall for that scorecard), and `ai_scorecard_rules`. For each rule when listed:22+ - `rule_name`: Title of the criterion.23+ - `rule_prompt`: The criterion text that was evaluated.24+ - `score`: Whole number **1–5** measuring how well the call satisfied that criterion against `rule_prompt` (1 = no evidence / not discussed or contrary; 5 = strong, clear evidence on the call).25+ - `justification`: Short rationale grounded in what happened on the call.26+ - `justification_timestamps`: Up to three entries with speaker **name** and **timestamp** (MM:SS in the recording) highlighting where the justification is supported.27+ - Use scores for coaching summaries, trends across calls, or quick comparisons when relevant. For **what was actually said**, still rely on the **transcript** (you may cross-reference rule timestamps when helpful).19- Use the Message History to:28- Use the Message History to:20 - Maintain continuity if the current question refers to previous exchanges.29 - Maintain continuity if the current question refers to previous exchanges.21 - Clarify or resolve ambiguities if the question depends on prior messages.30 - Clarify or resolve ambiguities if the question depends on prior messages.@@ -28,10 +37,10 @@ System instructions:28 - All factual claims must be supported by one or more references to relevant calls.37 - All factual claims must be supported by one or more references to relevant calls.29 - Use Markdown link syntax ([link text](URL)) and place links inline within sentences. Do not use footnotes, reference sections, or bare URLs. Integrate the reference links directly within the relevant parts of your response, rather than in a separate section.38 - Use Markdown link syntax ([link text](URL)) and place links inline within sentences. Do not use footnotes, reference sections, or bare URLs. Integrate the reference links directly within the relevant parts of your response, rather than in a separate section.30 - Use markdown links in the format [link text](/playback/{{call_id}})39 - Use markdown links in the format [link text](/playback/{{call_id}})31- - Use descriptive link that utlizes the call name. Do not use call time stamps in the link text even if the link itself contains a time stamp, e.g. use 'Call Name' instead of 'Call Name at 10:00'. Never use call ids as link text.\n"40+ - Use descriptive link text that utilizes the call name. Do not use call time stamps in the link text even if the link itself contains a time stamp, e.g. use 'Call Name' instead of 'Call Name at 10:00'. Never use call ids as link text.32- - Good example of link text: [Call Name](/playback/1234567890?apFrom=123)\n"41+ - Good example of link text: [Call Name](/playback/1234567890?apFrom=123)33- - Bad example of link text: [Call Name at 12:34](/playback/1234567890?apFrom=123) (do not use call time stamps in the link text)\n"42+ - Bad example of link text: [Call Name at 12:34](/playback/1234567890?apFrom=123) (do not use call time stamps in the link text)34- - Bad example of links: [Call Name on November 12, 2025](/playback/1234567890?apFrom=123) (do not use dates in the link text)\n\n"43+ - Bad example of links: [Call Name on November 12, 2025](/playback/1234567890?apFrom=123) (do not use dates in the link text)35 - You might back your statements with examples from the provided call transcripts in addition to the reference links.44 - You might back your statements with examples from the provided call transcripts in addition to the reference links.36- Be specific. Use names of accounts, clients and persons involved. Don't just say "one client" or "a client"! If no account is available, use the call title as a reference.45- Be specific. Use names of accounts, clients and persons involved. Don't just say "one client" or "a client"! If no account is available, use the call title as a reference.37- If the question or context is unclear, request clarification or highlight ambiguities.46- If the question or context is unclear, request clarification or highlight ambiguities.</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-20361: Add call scores in Panorama by steliyan-</tabTitle>” with “<selection>@@ -4,7 +4,7 @@ Today is {date_today}.445System instructions:5System instructions:6- You must answer using markdown. Do not use html tags in your response even if requested by the user's question.6- You must answer using markdown. Do not use html tags in your response even if requested by the user's question.7-- The contexts includes data for call shortlisted through user-applied filters. Note that the calls might not relate to the same deal or not even be by the same sales rep.7+- The context includes data for calls shortlisted through user-applied filters. Note that the calls might not relate to the same deal or not even be by the same sales rep.8 - The full call context includes all calls data available while the short call context contains only an overview of the calls that are analysed. Refer to the short call context for quick reference and to see the overall picture.8 - The full call context includes all calls data available while the short call context contains only an overview of the calls that are analysed. Refer to the short call context for quick reference and to see the overall picture.9- The calls are ordered in chronological order. 9- The calls are ordered in chronological order. 10- Here’s how to use the call context:10- Here’s how to use the call context:@@ -16,6 +16,15 @@ System instructions:16 - Frame answers with awareness of the company’s ICP, deal cycle, and sales motion.16 - Frame answers with awareness of the company’s ICP, deal cycle, and sales motion.17 - Evaluate statements or objections based on how the team operates and what success looks like.17 - Evaluate statements or objections based on how the team operates and what success looks like.18 - Position responses in light of known competitors and market dynamics.18 - Position responses in light of known competitors and market dynamics.19+ - AI call score (`ai_call_score` in the full call JSON): When present, treat it as **pre-computed** output from your team’s AI call-scoring pipeline (the same kind of scoring as the `/call/ai-call-scoring` endpoint). **Do not** invent, override, or recalculate scores; interpret and summarize what is given.20+ - **Short call context:** **AI Scorecard** is the name of the scorecard applied to that call; **AI Score** is the **overall** score for that scorecard (the average of its per-rule scores, possibly shown as a decimal).21+ - **Full call context:** The `ai_call_score` object may include `ai_scorecard_name`, `score` (overall for that scorecard), and `ai_scorecard_rules`. For each rule when listed:22+ - `rule_name`: Title of the criterion.23+ - `rule_prompt`: The criterion text that was evaluated.24+ - `score`: Whole number **1–5** measuring how well the call satisfied that criterion against `rule_prompt` (1 = no evidence / not discussed or contrary; 5 = strong, clear evidence on the call).25+ - `justification`: Short rationale grounded in what happened on the call.26+ - `justification_timestamps`: Up to three entries with speaker **name** and **timestamp** (MM:SS in the recording) highlighting where the justification is supported.27+ - Use scores for coaching summaries, trends across calls, or quick comparisons when relevant. For **what was actually said**, still rely on the **transcript** (you may cross-reference rule timestamps when helpful).19- Use the Message History to:28- Use the Message History to:20 - Maintain continuity if the current question refers to previous exchanges.29 - Maintain continuity if the current question refers to previous exchanges.21 - Clarify or resolve ambiguities if the question depends on prior messages.30 - Clarify or resolve ambiguities if the question depends on prior messages.@@ -28,10 +37,10 @@ System instructions:28 - All factual claims must be supported by one or more references to relevant calls.37 - All factual claims must be supported by one or more references to relevant calls.29 - Use Markdown link syntax ([link text](URL)) and place links inline within sentences. Do not use footnotes, reference sections, or bare URLs. Integrate the reference links directly within the relevant parts of your response, rather than in a separate section.38 - Use Markdown link syntax ([link text](URL)) and place links inline within sentences. Do not use footnotes, reference sections, or bare URLs. Integrate the reference links directly within the relevant parts of your response, rather than in a separate section.30 - Use markdown links in the format [link text](/playback/{{call_id}})39 - Use markdown links in the format [link text](/playback/{{call_id}})31- - Use descriptive link that utlizes the call name. Do not use call time stamps in the link text even if the link itself contains a time stamp, e.g. use 'Call Name' instead of 'Call Name at 10:00'. Never use call ids as link text.\n"40+ - Use descriptive link text that utilizes the call name. Do not use call time stamps in the link text even if the link itself contains a time stamp, e.g. use 'Call Name' instead of 'Call Name at 10:00'. Never use call ids as link text.32- - Good example of link text: [Call Name](/playback/1234567890?apFrom=123)\n"41+ - Good example of link text: [Call Name](/playback/1234567890?apFrom=123)33- - Bad example of link text: [Call Name at 12:34](/playback/1234567890?apFrom=123) (do not use call time stamps in the link text)\n"42+ - Bad example of link text: [Call Name at 12:34](/playback/1234567890?apFrom=123) (do not use call time stamps in the link text)34- - Bad example of links: [Call Name on November 12, 2025](/playback/1234567890?apFrom=123) (do not use dates in the link text)\n\n"43+ - Bad example of links: [Call Name on November 12, 2025](/playback/1234567890?apFrom=123) (do not use dates in the link text)35 - You might back your statements with examples from the provided call transcripts in addition to the reference links.44 - You might back your statements with examples from the provided call transcripts in addition to the reference links.36- Be specific. Use names of accounts, clients and persons involved. Don't just say "one client" or "a client"! If no account is available, use the call title as a reference.45- Be specific. Use names of accounts, clients and persons involved. Don't just say "one client" or "a client"! If no account is available, use the call title as a reference.37- If the question or context is unclear, request clarification or highlight ambiguities.46- If the question or context is unclear, request clarification or highlight ambiguities.</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.
Expand
Listen
Show thinking...
|
[{"role":"AXRadioButton","text [{"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":"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":"AXRadioButton","text":"[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - 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":"[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · 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-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · 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":"Pull requests · 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":"Pull requests · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20773] User Pilot not receiving events on report generated - 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":"[JY-20773] User Pilot not receiving events on report generated - Jira","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":"[JY-20776] Automated report - sentry - 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":"[JY-20776] Automated report - sentry - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — 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":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — 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":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app","depth":5,"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":"AXRadioButton","text":"JY-20361: Add call scores in Panorama by steliyan-g · Pull Request #507 · jiminny/prophet","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-20361: Add call scores in Panorama by steliyan-g · Pull Request #507 · jiminny/prophet","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"LLM API Pricing Comparison & Cost Guide (May 2026)","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"LLM API Pricing Comparison & Cost Guide (May 2026)","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":"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.019097222,"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.04236111,"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-20361: Add call scores in Panorama by steliyan-</tabTitle>” with “<selection>@@ -4,7 +4,7 @@ Today is {date_today}.445System instructions:5System instructions:6- You must answer using markdown. Do not use html tags in your response even if requested by the user's question.6- You must answer using markdown. Do not use html tags in your response even if requested by the user's question.7-- The contexts includes data for call shortlisted through user-applied filters. Note that the calls might not relate to the same deal or not even be by the same sales rep.7+- The context includes data for calls shortlisted through user-applied filters. Note that the calls might not relate to the same deal or not even be by the same sales rep.8 - The full call context includes all calls data available while the short call context contains only an overview of the calls that are analysed. Refer to the short call context for quick reference and to see the overall picture.8 - The full call context includes all calls data available while the short call context contains only an overview of the calls that are analysed. Refer to the short call context for quick reference and to see the overall picture.9- The calls are ordered in chronological order. 9- The calls are ordered in chronological order. 10- Here’s how to use the call context:10- Here’s how to use the call context:@@ -16,6 +16,15 @@ System instructions:16 - Frame answers with awareness of the company’s ICP, deal cycle, and sales motion.16 - Frame answers with awareness of the company’s ICP, deal cycle, and sales motion.17 - Evaluate statements or objections based on how the team operates and what success looks like.17 - Evaluate statements or objections based on how the team operates and what success looks like.18 - Position responses in light of known competitors and market dynamics.18 - Position responses in light of known competitors and market dynamics.19+ - AI call score (`ai_call_score` in the full call JSON): When present, treat it as **pre-computed** output from your team’s AI call-scoring pipeline (the same kind of scoring as the `/call/ai-call-scoring` endpoint). **Do not** invent, override, or recalculate scores; interpret and summarize what is given.20+ - **Short call context:** **AI Scorecard** is the name of the scorecard applied to that call; **AI Score** is the **overall** score for that scorecard (the average of its per-rule scores, possibly shown as a decimal).21+ - **Full call context:** The `ai_call_score` object may include `ai_scorecard_name`, `score` (overall for that scorecard), and `ai_scorecard_rules`. For each rule when listed:22+ - `rule_name`: Title of the criterion.23+ - `rule_prompt`: The criterion text that was evaluated.24+ - `score`: Whole number **1–5** measuring how well the call satisfied that criterion against `rule_prompt` (1 = no evidence / not discussed or contrary; 5 = strong, clear evidence on the call).25+ - `justification`: Short rationale grounded in what happened on the call.26+ - `justification_timestamps`: Up to three entries with speaker **name** and **timestamp** (MM:SS in the recording) highlighting where the justification is supported.27+ - Use scores for coaching summaries, trends across calls, or quick comparisons when relevant. For **what was actually said**, still rely on the **transcript** (you may cross-reference rule timestamps when helpful).19- Use the Message History to:28- Use the Message History to:20 - Maintain continuity if the current question refers to previous exchanges.29 - Maintain continuity if the current question refers to previous exchanges.21 - Clarify or resolve ambiguities if the question depends on prior messages.30 - Clarify or resolve ambiguities if the question depends on prior messages.@@ -28,10 +37,10 @@ System instructions:28 - All factual claims must be supported by one or more references to relevant calls.37 - All factual claims must be supported by one or more references to relevant calls.29 - Use Markdown link syntax ([link text](URL)) and place links inline within sentences. Do not use footnotes, reference sections, or bare URLs. Integrate the reference links directly within the relevant parts of your response, rather than in a separate section.38 - Use Markdown link syntax ([link text](URL)) and place links inline within sentences. Do not use footnotes, reference sections, or bare URLs. Integrate the reference links directly within the relevant parts of your response, rather than in a separate section.30 - Use markdown links in the format [link text](/playback/{{call_id}})39 - Use markdown links in the format [link text](/playback/{{call_id}})31- - Use descriptive link that utlizes the call name. Do not use call time stamps in the link text even if the link itself contains a time stamp, e.g. use 'Call Name' instead of 'Call Name at 10:00'. Never use call ids as link text.\\n"40+ - Use descriptive link text that utilizes the call name. Do not use call time stamps in the link text even if the link itself contains a time stamp, e.g. use 'Call Name' instead of 'Call Name at 10:00'. Never use call ids as link text.32- - Good example of link text: [Call Name](/playback/1234567890?apFrom=123)\\n"41+ - Good example of link text: [Call Name](/playback/1234567890?apFrom=123)33- - Bad example of link text: [Call Name at 12:34](/playback/1234567890?apFrom=123) (do not use call time stamps in the link text)\\n"42+ - Bad example of link text: [Call Name at 12:34](/playback/1234567890?apFrom=123) (do not use call time stamps in the link text)34- - Bad example of links: [Call Name on November 12, 2025](/playback/1234567890?apFrom=123) (do not use dates in the link text)\\n\\n"43+ - Bad example of links: [Call Name on November 12, 2025](/playback/1234567890?apFrom=123) (do not use dates in the link text)35 - You might back your statements with examples from the provided call transcripts in addition to the reference links.44 - You might back your statements with examples from the provided call transcripts in addition to the reference links.36- Be specific. Use names of accounts, clients and persons involved. Don't just say "one client" or "a client"! If no account is available, use the call title as a reference.45- Be specific. Use names of accounts, clients and persons involved. Don't just say "one client" or "a client"! If no account is available, use the call title as a reference.37- If the question or context is unclear, request clarification or highlight ambiguities.46- If the question or context is unclear, request clarification or highlight ambiguities.</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-20361: Add call scores in Panorama by steliyan-</tabTitle>” with “<selection>@@ -4,7 +4,7 @@ Today is {date_today}.445System instructions:5System instructions:6- You must answer using markdown. Do not use html tags in your response even if requested by the user's question.6- You must answer using markdown. Do not use html tags in your response even if requested by the user's question.7-- The contexts includes data for call shortlisted through user-applied filters. Note that the calls might not relate to the same deal or not even be by the same sales rep.7+- The context includes data for calls shortlisted through user-applied filters. Note that the calls might not relate to the same deal or not even be by the same sales rep.8 - The full call context includes all calls data available while the short call context contains only an overview of the calls that are analysed. Refer to the short call context for quick reference and to see the overall picture.8 - The full call context includes all calls data available while the short call context contains only an overview of the calls that are analysed. Refer to the short call context for quick reference and to see the overall picture.9- The calls are ordered in chronological order. 9- The calls are ordered in chronological order. 10- Here’s how to use the call context:10- Here’s how to use the call context:@@ -16,6 +16,15 @@ System instructions:16 - Frame answers with awareness of the company’s ICP, deal cycle, and sales motion.16 - Frame answers with awareness of the company’s ICP, deal cycle, and sales motion.17 - Evaluate statements or objections based on how the team operates and what success looks like.17 - Evaluate statements or objections based on how the team operates and what success looks like.18 - Position responses in light of known competitors and market dynamics.18 - Position responses in light of known competitors and market dynamics.19+ - AI call score (`ai_call_score` in the full call JSON): When present, treat it as **pre-computed** output from your team’s AI call-scoring pipeline (the same kind of scoring as the `/call/ai-call-scoring` endpoint). **Do not** invent, override, or recalculate scores; interpret and summarize what is given.20+ - **Short call context:** **AI Scorecard** is the name of the scorecard applied to that call; **AI Score** is the **overall** score for that scorecard (the average of its per-rule scores, possibly shown as a decimal).21+ - **Full call context:** The `ai_call_score` object may include `ai_scorecard_name`, `score` (overall for that scorecard), and `ai_scorecard_rules`. For each rule when listed:22+ - `rule_name`: Title of the criterion.23+ - `rule_prompt`: The criterion text that was evaluated.24+ - `score`: Whole number **1–5** measuring how well the call satisfied that criterion against `rule_prompt` (1 = no evidence / not discussed or contrary; 5 = strong, clear evidence on the call).25+ - `justification`: Short rationale grounded in what happened on the call.26+ - `justification_timestamps`: Up to three entries with speaker **name** and **timestamp** (MM:SS in the recording) highlighting where the justification is supported.27+ - Use scores for coaching summaries, trends across calls, or quick comparisons when relevant. For **what was actually said**, still rely on the **transcript** (you may cross-reference rule timestamps when helpful).19- Use the Message History to:28- Use the Message History to:20 - Maintain continuity if the current question refers to previous exchanges.29 - Maintain continuity if the current question refers to previous exchanges.21 - Clarify or resolve ambiguities if the question depends on prior messages.30 - Clarify or resolve ambiguities if the question depends on prior messages.@@ -28,10 +37,10 @@ System instructions:28 - All factual claims must be supported by one or more references to relevant calls.37 - All factual claims must be supported by one or more references to relevant calls.29 - Use Markdown link syntax ([link text](URL)) and place links inline within sentences. Do not use footnotes, reference sections, or bare URLs. Integrate the reference links directly within the relevant parts of your response, rather than in a separate section.38 - Use Markdown link syntax ([link text](URL)) and place links inline within sentences. Do not use footnotes, reference sections, or bare URLs. Integrate the reference links directly within the relevant parts of your response, rather than in a separate section.30 - Use markdown links in the format [link text](/playback/{{call_id}})39 - Use markdown links in the format [link text](/playback/{{call_id}})31- - Use descriptive link that utlizes the call name. Do not use call time stamps in the link text even if the link itself contains a time stamp, e.g. use 'Call Name' instead of 'Call Name at 10:00'. Never use call ids as link text.\\n"40+ - Use descriptive link text that utilizes the call name. Do not use call time stamps in the link text even if the link itself contains a time stamp, e.g. use 'Call Name' instead of 'Call Name at 10:00'. Never use call ids as link text.32- - Good example of link text: [Call Name](/playback/1234567890?apFrom=123)\\n"41+ - Good example of link text: [Call Name](/playback/1234567890?apFrom=123)33- - Bad example of link text: [Call Name at 12:34](/playback/1234567890?apFrom=123) (do not use call time stamps in the link text)\\n"42+ - Bad example of link text: [Call Name at 12:34](/playback/1234567890?apFrom=123) (do not use call time stamps in the link text)34- - Bad example of links: [Call Name on November 12, 2025](/playback/1234567890?apFrom=123) (do not use dates in the link text)\\n\\n"43+ - Bad example of links: [Call Name on November 12, 2025](/playback/1234567890?apFrom=123) (do not use dates in the link text)35 - You might back your statements with examples from the provided call transcripts in addition to the reference links.44 - You might back your statements with examples from the provided call transcripts in addition to the reference links.36- Be specific. Use names of accounts, clients and persons involved. Don't just say "one client" or "a client"! If no account is available, use the call title as a reference.45- Be specific. Use names of accounts, clients and persons involved. Don't just say "one client" or "a client"! If no account is available, use the call title as a reference.37- If the question or context is unclear, request clarification or highlight ambiguities.46- If the question or context is unclear, request clarification or highlight ambiguities.</selection>” selected.","depth":23,"on_screen":true,"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":"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":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-8078048077180658791
|
-2831912997475075182
|
visual_change
|
accessibility
|
NULL
|
New Tab
New Tab
Jy 20820 es reindex stream model h New Tab
New Tab
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Pull requests · jiminny/app
Pull requests · jiminny/app
[JY-20773] User Pilot not receiving events on report generated - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
JY-20361: Add call scores in Panorama by steliyan-g · Pull Request #507 · jiminny/prophet
JY-20361: Add call scores in Panorama by steliyan-g · Pull Request #507 · jiminny/prophet
LLM API Pricing Comparison & Cost Guide (May 2026)
LLM API Pricing Comparison & Cost Guide (May 2026)
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Copy prompt
You said I’m on page “<tabTitle>JY-20361: Add call scores in Panorama by steliyan-</tabTitle>” with “<selection>@@ -4,7 +4,7 @@ Today is {date_today}.445System instructions:5System instructions:6- You must answer using markdown. Do not use html tags in your response even if requested by the user's question.6- You must answer using markdown. Do not use html tags in your response even if requested by the user's question.7-- The contexts includes data for call shortlisted through user-applied filters. Note that the calls might not relate to the same deal or not even be by the same sales rep.7+- The context includes data for calls shortlisted through user-applied filters. Note that the calls might not relate to the same deal or not even be by the same sales rep.8 - The full call context includes all calls data available while the short call context contains only an overview of the calls that are analysed. Refer to the short call context for quick reference and to see the overall picture.8 - The full call context includes all calls data available while the short call context contains only an overview of the calls that are analysed. Refer to the short call context for quick reference and to see the overall picture.9- The calls are ordered in chronological order. 9- The calls are ordered in chronological order. 10- Here’s how to use the call context:10- Here’s how to use the call context:@@ -16,6 +16,15 @@ System instructions:16 - Frame answers with awareness of the company’s ICP, deal cycle, and sales motion.16 - Frame answers with awareness of the company’s ICP, deal cycle, and sales motion.17 - Evaluate statements or objections based on how the team operates and what success looks like.17 - Evaluate statements or objections based on how the team operates and what success looks like.18 - Position responses in light of known competitors and market dynamics.18 - Position responses in light of known competitors and market dynamics.19+ - AI call score (`ai_call_score` in the full call JSON): When present, treat it as **pre-computed** output from your team’s AI call-scoring pipeline (the same kind of scoring as the `/call/ai-call-scoring` endpoint). **Do not** invent, override, or recalculate scores; interpret and summarize what is given.20+ - **Short call context:** **AI Scorecard** is the name of the scorecard applied to that call; **AI Score** is the **overall** score for that scorecard (the average of its per-rule scores, possibly shown as a decimal).21+ - **Full call context:** The `ai_call_score` object may include `ai_scorecard_name`, `score` (overall for that scorecard), and `ai_scorecard_rules`. For each rule when listed:22+ - `rule_name`: Title of the criterion.23+ - `rule_prompt`: The criterion text that was evaluated.24+ - `score`: Whole number **1–5** measuring how well the call satisfied that criterion against `rule_prompt` (1 = no evidence / not discussed or contrary; 5 = strong, clear evidence on the call).25+ - `justification`: Short rationale grounded in what happened on the call.26+ - `justification_timestamps`: Up to three entries with speaker **name** and **timestamp** (MM:SS in the recording) highlighting where the justification is supported.27+ - Use scores for coaching summaries, trends across calls, or quick comparisons when relevant. For **what was actually said**, still rely on the **transcript** (you may cross-reference rule timestamps when helpful).19- Use the Message History to:28- Use the Message History to:20 - Maintain continuity if the current question refers to previous exchanges.29 - Maintain continuity if the current question refers to previous exchanges.21 - Clarify or resolve ambiguities if the question depends on prior messages.30 - Clarify or resolve ambiguities if the question depends on prior messages.@@ -28,10 +37,10 @@ System instructions:28 - All factual claims must be supported by one or more references to relevant calls.37 - All factual claims must be supported by one or more references to relevant calls.29 - Use Markdown link syntax ([link text](URL)) and place links inline within sentences. Do not use footnotes, reference sections, or bare URLs. Integrate the reference links directly within the relevant parts of your response, rather than in a separate section.38 - Use Markdown link syntax ([link text](URL)) and place links inline within sentences. Do not use footnotes, reference sections, or bare URLs. Integrate the reference links directly within the relevant parts of your response, rather than in a separate section.30 - Use markdown links in the format [link text](/playback/{{call_id}})39 - Use markdown links in the format [link text](/playback/{{call_id}})31- - Use descriptive link that utlizes the call name. Do not use call time stamps in the link text even if the link itself contains a time stamp, e.g. use 'Call Name' instead of 'Call Name at 10:00'. Never use call ids as link text.\n"40+ - Use descriptive link text that utilizes the call name. Do not use call time stamps in the link text even if the link itself contains a time stamp, e.g. use 'Call Name' instead of 'Call Name at 10:00'. Never use call ids as link text.32- - Good example of link text: [Call Name](/playback/1234567890?apFrom=123)\n"41+ - Good example of link text: [Call Name](/playback/1234567890?apFrom=123)33- - Bad example of link text: [Call Name at 12:34](/playback/1234567890?apFrom=123) (do not use call time stamps in the link text)\n"42+ - Bad example of link text: [Call Name at 12:34](/playback/1234567890?apFrom=123) (do not use call time stamps in the link text)34- - Bad example of links: [Call Name on November 12, 2025](/playback/1234567890?apFrom=123) (do not use dates in the link text)\n\n"43+ - Bad example of links: [Call Name on November 12, 2025](/playback/1234567890?apFrom=123) (do not use dates in the link text)35 - You might back your statements with examples from the provided call transcripts in addition to the reference links.44 - You might back your statements with examples from the provided call transcripts in addition to the reference links.36- Be specific. Use names of accounts, clients and persons involved. Don't just say "one client" or "a client"! If no account is available, use the call title as a reference.45- Be specific. Use names of accounts, clients and persons involved. Don't just say "one client" or "a client"! If no account is available, use the call title as a reference.37- If the question or context is unclear, request clarification or highlight ambiguities.46- If the question or context is unclear, request clarification or highlight ambiguities.</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-20361: Add call scores in Panorama by steliyan-</tabTitle>” with “<selection>@@ -4,7 +4,7 @@ Today is {date_today}.445System instructions:5System instructions:6- You must answer using markdown. Do not use html tags in your response even if requested by the user's question.6- You must answer using markdown. Do not use html tags in your response even if requested by the user's question.7-- The contexts includes data for call shortlisted through user-applied filters. Note that the calls might not relate to the same deal or not even be by the same sales rep.7+- The context includes data for calls shortlisted through user-applied filters. Note that the calls might not relate to the same deal or not even be by the same sales rep.8 - The full call context includes all calls data available while the short call context contains only an overview of the calls that are analysed. Refer to the short call context for quick reference and to see the overall picture.8 - The full call context includes all calls data available while the short call context contains only an overview of the calls that are analysed. Refer to the short call context for quick reference and to see the overall picture.9- The calls are ordered in chronological order. 9- The calls are ordered in chronological order. 10- Here’s how to use the call context:10- Here’s how to use the call context:@@ -16,6 +16,15 @@ System instructions:16 - Frame answers with awareness of the company’s ICP, deal cycle, and sales motion.16 - Frame answers with awareness of the company’s ICP, deal cycle, and sales motion.17 - Evaluate statements or objections based on how the team operates and what success looks like.17 - Evaluate statements or objections based on how the team operates and what success looks like.18 - Position responses in light of known competitors and market dynamics.18 - Position responses in light of known competitors and market dynamics.19+ - AI call score (`ai_call_score` in the full call JSON): When present, treat it as **pre-computed** output from your team’s AI call-scoring pipeline (the same kind of scoring as the `/call/ai-call-scoring` endpoint). **Do not** invent, override, or recalculate scores; interpret and summarize what is given.20+ - **Short call context:** **AI Scorecard** is the name of the scorecard applied to that call; **AI Score** is the **overall** score for that scorecard (the average of its per-rule scores, possibly shown as a decimal).21+ - **Full call context:** The `ai_call_score` object may include `ai_scorecard_name`, `score` (overall for that scorecard), and `ai_scorecard_rules`. For each rule when listed:22+ - `rule_name`: Title of the criterion.23+ - `rule_prompt`: The criterion text that was evaluated.24+ - `score`: Whole number **1–5** measuring how well the call satisfied that criterion against `rule_prompt` (1 = no evidence / not discussed or contrary; 5 = strong, clear evidence on the call).25+ - `justification`: Short rationale grounded in what happened on the call.26+ - `justification_timestamps`: Up to three entries with speaker **name** and **timestamp** (MM:SS in the recording) highlighting where the justification is supported.27+ - Use scores for coaching summaries, trends across calls, or quick comparisons when relevant. For **what was actually said**, still rely on the **transcript** (you may cross-reference rule timestamps when helpful).19- Use the Message History to:28- Use the Message History to:20 - Maintain continuity if the current question refers to previous exchanges.29 - Maintain continuity if the current question refers to previous exchanges.21 - Clarify or resolve ambiguities if the question depends on prior messages.30 - Clarify or resolve ambiguities if the question depends on prior messages.@@ -28,10 +37,10 @@ System instructions:28 - All factual claims must be supported by one or more references to relevant calls.37 - All factual claims must be supported by one or more references to relevant calls.29 - Use Markdown link syntax ([link text](URL)) and place links inline within sentences. Do not use footnotes, reference sections, or bare URLs. Integrate the reference links directly within the relevant parts of your response, rather than in a separate section.38 - Use Markdown link syntax ([link text](URL)) and place links inline within sentences. Do not use footnotes, reference sections, or bare URLs. Integrate the reference links directly within the relevant parts of your response, rather than in a separate section.30 - Use markdown links in the format [link text](/playback/{{call_id}})39 - Use markdown links in the format [link text](/playback/{{call_id}})31- - Use descriptive link that utlizes the call name. Do not use call time stamps in the link text even if the link itself contains a time stamp, e.g. use 'Call Name' instead of 'Call Name at 10:00'. Never use call ids as link text.\n"40+ - Use descriptive link text that utilizes the call name. Do not use call time stamps in the link text even if the link itself contains a time stamp, e.g. use 'Call Name' instead of 'Call Name at 10:00'. Never use call ids as link text.32- - Good example of link text: [Call Name](/playback/1234567890?apFrom=123)\n"41+ - Good example of link text: [Call Name](/playback/1234567890?apFrom=123)33- - Bad example of link text: [Call Name at 12:34](/playback/1234567890?apFrom=123) (do not use call time stamps in the link text)\n"42+ - Bad example of link text: [Call Name at 12:34](/playback/1234567890?apFrom=123) (do not use call time stamps in the link text)34- - Bad example of links: [Call Name on November 12, 2025](/playback/1234567890?apFrom=123) (do not use dates in the link text)\n\n"43+ - Bad example of links: [Call Name on November 12, 2025](/playback/1234567890?apFrom=123) (do not use dates in the link text)35 - You might back your statements with examples from the provided call transcripts in addition to the reference links.44 - You might back your statements with examples from the provided call transcripts in addition to the reference links.36- Be specific. Use names of accounts, clients and persons involved. Don't just say "one client" or "a client"! If no account is available, use the call title as a reference.45- Be specific. Use names of accounts, clients and persons involved. Don't just say "one client" or "a client"! If no account is available, use the call title as a reference.37- If the question or context is unclear, request clarification or highlight ambiguities.46- If the question or context is unclear, request clarification or highlight ambiguities.</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.
Expand
Listen
Show thinking...
|
22290
|
NULL
|
NULL
|
NULL
|
|
8720
|
390
|
1
|
2026-05-08T11:16:03.787478+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778238963787_m2.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhostormcodeFV faVsco.jsProledey(C) CrmActivitySer PhostormcodeFV faVsco.jsProledey(C) CrmActivityService.php©.Timezonereposttory.onp© TopicRepository.php© TopicTriggerRepository.ph|© TrackRepository.php(C) TranccrintionModell ocale?© RateLimitException.phpoCllentonpxhandlenuospotkateLlmic.ong© MatchCrmData.php© CrmObjectsResolver.php© TranscriptionRepository.ph© TranscriptionSummaryRepc© UserRepository.phpclass Client extends BaseClient implements HubspotClientInterface=public function getAssociationsData(array $ids, string $from0bject, string $to0bject): arrayA2M64.TAYc Vocabularykepository.pnp> C Rulesv @ Services>D ACUVILY> D AiReports> Avaran07 Calendar› conterencev 0 Crm) BullhornCloseI CooneCrmObiects969N DecorateActivitv971Dummy1 Helners• m Hubsnot• AccountSyncStrateg:975>M ActioncD ContactSyncStrateg)MnTOm FieldsM.lournalMotadato>@ OpportunitySyncStrav @ Pagination© HubspotPaginatio© PaginationConfig.C) PaqinationState.p> 0 ProspectSearchStrat>D Redisv W ServiceTraits() OpportunitvSvncT 999() SvncCrmEntitiesTiTSvncFieldstirait.of(t) WriteCrmTrait.ohr• M UtilsN WebhookC) BatchSvncCollector.r oog(c) RatchSvncRedicServforeach (SidChunks as SidChunk){sbatchinput = new (Hubspot\cl1ent\crm\Assoclations Model BatchlnputPubL1c0bgectld:Sbatchinput->setinputs(arrav_mapfunction S10) 4.... S1dChunk)0^Sassochatedobnectslata = sthls->aetNewiinstance@->crmol->associationsol->batchAniol->rpadiisfromhhrect, Stolhrect, Shatchinnut):if (SassociatedObjectsData instanceof |HubSpot\CLient\Crm/Associations|Model|BatchResponsePun 20foreach (Sassociated0bjectsData->getResults( as Sassociation) ‹$from = Sassociation->getFrom->getIdO:$toAssociations = Sassociation->getTo@:=24if (! empty($toAssociations)) {SassociationData[$from] = array_map(function (Sitem) {...}, StoAssociations):} catch (RateLimitException Se) {throw se:catch Exception se) "Sthis->log->error('[Hubspot] Failed to fetch associations'. ['trom obnect' => "tromubnect..'reason' => se->qetMessage@return Sassociationhata:• Athrows Excentionprivate function getNoteAssociationType(Note0bject $note0bject): string{...}(C) CiocedDea|StadecSe 100d@ DealFieldeService nh 100dSupport Daily - in 44 m100% 12Fri 8 May 14:16:04U AskJiminnyReportActivityServiceTest v+0 ..4 SF jiminny@localhost]A HS_local [jiminny@localhost]# console [PKol)A console [EU]A console [STAGING][2026-05-07 14:21:15] local.INF0: [Hubspot] DEBUG Getting headers {"neaders".?"Uace"."Inu,or May 2020 14.21.15 6Ml"Jn"concenc-lyoe. apolicacionison.charser=uct-o.n"Transter-encoding":"chunked","CF-Ray":"9t80deb8dbo0dcsa-S0F""Strict-Transport-Secur1ty":"max-aqe=31536008* 1ncLudeSubDomains: preload").acceot-encodino""server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\","x-content-type-options": ["nosniff"],"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],"Set-Cookie":["__cf_bm=StUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxT07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],"Renont-To".f"y"endnoints".\"url\":\"https:|\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgl\"group\":\"cf-nel\".\"max_age\":604800}"],"NEL":["{\"success_fraction\":0.01,reportco. "cr-nel,"max age| ":604800}"]."Server": ["cloudflare"]}} {"correlation_1d": "95256555-ec98-4541-D92a-adta/Sboyead","trace_10":C/AD8565-905t-4604-9405-0e5b551e5545'Hubspot Rate LimitingHubSpot Rate Limit ReClient.php:29/-316Sbatchcontia = Sthis->createBatchContiquration Sobiecttype=SbatchReadRequest = Sthis->orepareBatchRequest(SbatchConfila. Scrmids. Stields):$response = $batchConfig['api']->read($batchReadRequest);batchReadObiects calls the SDK directly. A 429 here will throw a raw Dea ApiException/ CompanyApiException/ ContactApiException , which handle- BatchError catches and wraps in CrmException - swallowing the rate limit signal entirely. Any job calling getOpportunitiesByIds, getCompanieFix: wrap the $batchConfig('api']→>read(...) call in $this->executeRequest(fn() = ...).getOpportunityById. getAccountById, getContactById, getContactByEmail, fetchProperty. fetch0pportunityPipelineStages. updateEngagement, getEngagementData, createEngagement, deleteEngagement, getMeeting, getAssociationsData - all bypass executeRequestThese all call getNewInstance()→>... or getInstance()->... directly. A 429 on any of them will propagate as a raw SDK exception, not a RateLimitException. The middleware cannot catch it.Since you said other jobs won't be modified now, this matters most for the methods called from MatchActivityCrmData's call chain. The search()path is covered - but if updateCrmData internally calls any of those other methods and gets a 429, it escapes the middleware,• makeRequest bypasses executeRequestClient.pho:744-771makeRequest (and everything using it: createMeeting, updateMeeting, addAssociations, removeAssociations, fetchOpportunityPipelines) hasdebua loggina left in production code.\Illuminate\Support\Facades\Log:: channel('custom_channel')->info('$max' ...\Illuminate\Support\Facades\Log:: channel('custom_channel')->info('Sremaining' ...IlLuminate Support Facades Loa:: channel('custom channel")->infoSinterval ...\Illuminate\Support\Facades\Log:: channel('custom_channel')->info('$body' ...This logs every API response body to a custom channel - including sensitive contact/deal data - on every call. This is clearly leftover debug codeand must be removed.A getAssociationsData silently swallows rate limit errorsClient.php:1005-1011n pho} catch (\Exception se) ‹$this->log->error('(Hubspot) Failed to fetch associations', [...]);A 429 here is caught, logged, and the loop continues to the next chunk. The caller gets a partial (silently incomplete) result with no indication thatrate limiting occurred.A parseRetryAfter calls getResponseBody() twice, decoding JSON twiceClient.oho: 122-154The body is decoded in block 1 (lines 124-136), then decoded again identically in block 2 (lines 140-154). The second block only adds the context.nolicwame check. Merae them into one decodeAisHubsnotRatel imit uses netcode() — fracileClient.php: 103-106Ask anvthing (8+D)<> CodeC° AdantiveW Windsurf Toams 002-1UTF.8io 4 spaces...
|
NULL
|
-8078006664663256896
|
NULL
|
click
|
ocr
|
NULL
|
PhostormcodeFV faVsco.jsProledey(C) CrmActivitySer PhostormcodeFV faVsco.jsProledey(C) CrmActivityService.php©.Timezonereposttory.onp© TopicRepository.php© TopicTriggerRepository.ph|© TrackRepository.php(C) TranccrintionModell ocale?© RateLimitException.phpoCllentonpxhandlenuospotkateLlmic.ong© MatchCrmData.php© CrmObjectsResolver.php© TranscriptionRepository.ph© TranscriptionSummaryRepc© UserRepository.phpclass Client extends BaseClient implements HubspotClientInterface=public function getAssociationsData(array $ids, string $from0bject, string $to0bject): arrayA2M64.TAYc Vocabularykepository.pnp> C Rulesv @ Services>D ACUVILY> D AiReports> Avaran07 Calendar› conterencev 0 Crm) BullhornCloseI CooneCrmObiects969N DecorateActivitv971Dummy1 Helners• m Hubsnot• AccountSyncStrateg:975>M ActioncD ContactSyncStrateg)MnTOm FieldsM.lournalMotadato>@ OpportunitySyncStrav @ Pagination© HubspotPaginatio© PaginationConfig.C) PaqinationState.p> 0 ProspectSearchStrat>D Redisv W ServiceTraits() OpportunitvSvncT 999() SvncCrmEntitiesTiTSvncFieldstirait.of(t) WriteCrmTrait.ohr• M UtilsN WebhookC) BatchSvncCollector.r oog(c) RatchSvncRedicServforeach (SidChunks as SidChunk){sbatchinput = new (Hubspot\cl1ent\crm\Assoclations Model BatchlnputPubL1c0bgectld:Sbatchinput->setinputs(arrav_mapfunction S10) 4.... S1dChunk)0^Sassochatedobnectslata = sthls->aetNewiinstance@->crmol->associationsol->batchAniol->rpadiisfromhhrect, Stolhrect, Shatchinnut):if (SassociatedObjectsData instanceof |HubSpot\CLient\Crm/Associations|Model|BatchResponsePun 20foreach (Sassociated0bjectsData->getResults( as Sassociation) ‹$from = Sassociation->getFrom->getIdO:$toAssociations = Sassociation->getTo@:=24if (! empty($toAssociations)) {SassociationData[$from] = array_map(function (Sitem) {...}, StoAssociations):} catch (RateLimitException Se) {throw se:catch Exception se) "Sthis->log->error('[Hubspot] Failed to fetch associations'. ['trom obnect' => "tromubnect..'reason' => se->qetMessage@return Sassociationhata:• Athrows Excentionprivate function getNoteAssociationType(Note0bject $note0bject): string{...}(C) CiocedDea|StadecSe 100d@ DealFieldeService nh 100dSupport Daily - in 44 m100% 12Fri 8 May 14:16:04U AskJiminnyReportActivityServiceTest v+0 ..4 SF jiminny@localhost]A HS_local [jiminny@localhost]# console [PKol)A console [EU]A console [STAGING][2026-05-07 14:21:15] local.INF0: [Hubspot] DEBUG Getting headers {"neaders".?"Uace"."Inu,or May 2020 14.21.15 6Ml"Jn"concenc-lyoe. apolicacionison.charser=uct-o.n"Transter-encoding":"chunked","CF-Ray":"9t80deb8dbo0dcsa-S0F""Strict-Transport-Secur1ty":"max-aqe=31536008* 1ncLudeSubDomains: preload").acceot-encodino""server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\","x-content-type-options": ["nosniff"],"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],"Set-Cookie":["__cf_bm=StUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxT07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],"Renont-To".f"y"endnoints".\"url\":\"https:|\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgl\"group\":\"cf-nel\".\"max_age\":604800}"],"NEL":["{\"success_fraction\":0.01,reportco. "cr-nel,"max age| ":604800}"]."Server": ["cloudflare"]}} {"correlation_1d": "95256555-ec98-4541-D92a-adta/Sboyead","trace_10":C/AD8565-905t-4604-9405-0e5b551e5545'Hubspot Rate LimitingHubSpot Rate Limit ReClient.php:29/-316Sbatchcontia = Sthis->createBatchContiquration Sobiecttype=SbatchReadRequest = Sthis->orepareBatchRequest(SbatchConfila. Scrmids. Stields):$response = $batchConfig['api']->read($batchReadRequest);batchReadObiects calls the SDK directly. A 429 here will throw a raw Dea ApiException/ CompanyApiException/ ContactApiException , which handle- BatchError catches and wraps in CrmException - swallowing the rate limit signal entirely. Any job calling getOpportunitiesByIds, getCompanieFix: wrap the $batchConfig('api']→>read(...) call in $this->executeRequest(fn() = ...).getOpportunityById. getAccountById, getContactById, getContactByEmail, fetchProperty. fetch0pportunityPipelineStages. updateEngagement, getEngagementData, createEngagement, deleteEngagement, getMeeting, getAssociationsData - all bypass executeRequestThese all call getNewInstance()→>... or getInstance()->... directly. A 429 on any of them will propagate as a raw SDK exception, not a RateLimitException. The middleware cannot catch it.Since you said other jobs won't be modified now, this matters most for the methods called from MatchActivityCrmData's call chain. The search()path is covered - but if updateCrmData internally calls any of those other methods and gets a 429, it escapes the middleware,• makeRequest bypasses executeRequestClient.pho:744-771makeRequest (and everything using it: createMeeting, updateMeeting, addAssociations, removeAssociations, fetchOpportunityPipelines) hasdebua loggina left in production code.\Illuminate\Support\Facades\Log:: channel('custom_channel')->info('$max' ...\Illuminate\Support\Facades\Log:: channel('custom_channel')->info('Sremaining' ...IlLuminate Support Facades Loa:: channel('custom channel")->infoSinterval ...\Illuminate\Support\Facades\Log:: channel('custom_channel')->info('$body' ...This logs every API response body to a custom channel - including sensitive contact/deal data - on every call. This is clearly leftover debug codeand must be removed.A getAssociationsData silently swallows rate limit errorsClient.php:1005-1011n pho} catch (\Exception se) ‹$this->log->error('(Hubspot) Failed to fetch associations', [...]);A 429 here is caught, logged, and the loop continues to the next chunk. The caller gets a partial (silently incomplete) result with no indication thatrate limiting occurred.A parseRetryAfter calls getResponseBody() twice, decoding JSON twiceClient.oho: 122-154The body is decoded in block 1 (lines 124-136), then decoded again identically in block 2 (lines 140-154). The second block only adds the context.nolicwame check. Merae them into one decodeAisHubsnotRatel imit uses netcode() — fracileClient.php: 103-106Ask anvthing (8+D)<> CodeC° AdantiveW Windsurf Toams 002-1UTF.8io 4 spaces...
|
8718
|
NULL
|
NULL
|
NULL
|
|
27795
|
NULL
|
0
|
2026-05-12T14:39:05.131930+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-12/1778 /Users/lukas/.screenpipe/data/data/2026-05-12/1778596745131_m2.jpg...
|
Finder
|
Work
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
/Users/lukas/.screenpipe/data/data/2026-05-12/1778 /Users/lukas/.screenpipe/data/data/2026-05-12/1778596745131_m2.jpg...
|
Favourites
jiminny
AirDrop
Recents
Applications
Do Favourites
jiminny
AirDrop
Recents
Applications
Documents
Downloads
lukas
iCloud
iCloud Drive
Sync folder
Locations
DXP4800PLUS-B5F
Eject
Network
Tags
CRM
Orange
Red
Yellow
Green
Blue
Purple
All Tags…
Name
Date Modified
Size
Kind
2026
Today at 17:39
--
Folder
Retro 2026-05-12.mp4
Today at 17:36
1,03 GB
MPEG-4 movie
Daily 2026-05-12.mp4
Today at 10:13
1,02 GB
MPEG-4 movie
PLanhat Petko interest event 2026-05-11.mp4
Yesterday at 12:22
144,5 MB
MPEG-4 movie
Daily 2026-05-11.mp4
Yesterday at 10:02
491,3 MB
MPEG-4 movie
Daily 2026-05-08.mp4
8 May 2026 at 10:22
1,37 GB
MPEG-4 movie...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Favourites","depth":6,"bounds":{"left":0.004654255,"top":0.061452515,"width":0.06216755,"height":0.015163607},"on_screen":true,"automation_id":"xSidebarHeader","role_description":"text"},{"role":"AXStaticText","text":"jiminny","depth":6,"bounds":{"left":0.012632979,"top":0.08140463,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"AirDrop","depth":6,"bounds":{"left":0.012632979,"top":0.103751,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Recents","depth":6,"bounds":{"left":0.012632979,"top":0.12609737,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Applications","depth":6,"bounds":{"left":0.012632979,"top":0.14844373,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Documents","depth":6,"bounds":{"left":0.012632979,"top":0.1707901,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Downloads","depth":6,"bounds":{"left":0.012632979,"top":0.19313647,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"lukas","depth":6,"bounds":{"left":0.012632979,"top":0.21548285,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"iCloud","depth":6,"bounds":{"left":0.004654255,"top":0.2434158,"width":0.06216755,"height":0.015163607},"on_screen":true,"automation_id":"xSidebarHeader","role_description":"text"},{"role":"AXStaticText","text":"iCloud Drive","depth":6,"bounds":{"left":0.012632979,"top":0.26336792,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Sync folder","depth":6,"bounds":{"left":0.012632979,"top":0.2857143,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Locations","depth":6,"bounds":{"left":0.004654255,"top":0.31364724,"width":0.06216755,"height":0.015163607},"on_screen":true,"automation_id":"xSidebarHeader","role_description":"text"},{"role":"AXStaticText","text":"DXP4800PLUS-B5F","depth":6,"bounds":{"left":0.012632979,"top":0.33359936,"width":0.043218084,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Eject","depth":6,"bounds":{"left":0.05651596,"top":0.33519554,"width":0.0043218085,"height":0.009577015},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXStaticText","text":"Network","depth":6,"bounds":{"left":0.012632979,"top":0.35594574,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Tags","depth":6,"bounds":{"left":0.004654255,"top":0.38387868,"width":0.06216755,"height":0.015163607},"on_screen":true,"automation_id":"xSidebarHeader","role_description":"text"},{"role":"AXStaticText","text":"CRM","depth":6,"bounds":{"left":0.012632979,"top":0.4038308,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Orange","depth":6,"bounds":{"left":0.012632979,"top":0.42617717,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Red","depth":6,"bounds":{"left":0.012632979,"top":0.44852355,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Yellow","depth":6,"bounds":{"left":0.012632979,"top":0.4708699,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Green","depth":6,"bounds":{"left":0.012632979,"top":0.49321628,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Blue","depth":6,"bounds":{"left":0.012632979,"top":0.51556265,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Purple","depth":6,"bounds":{"left":0.012632979,"top":0.53790903,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"All Tags…","depth":6,"bounds":{"left":0.012632979,"top":0.5602554,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Name","depth":7,"bounds":{"left":0.08277926,"top":0.06624102,"width":0.011635638,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Date Modified","depth":7,"bounds":{"left":0.36569148,"top":0.06624102,"width":0.026928192,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Size","depth":7,"bounds":{"left":0.42586437,"top":0.06624102,"width":0.008976064,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Kind","depth":7,"bounds":{"left":0.4581117,"top":0.06624102,"width":0.00930851,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"2026","depth":7,"bounds":{"left":0.08277926,"top":0.08938547,"width":0.013297873,"height":0.012769354},"on_screen":true,"value":"2026","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Today at 17:39","depth":7,"bounds":{"left":0.36569148,"top":0.08938547,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"--","depth":7,"bounds":{"left":0.44946808,"top":0.08938547,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":7,"bounds":{"left":0.4581117,"top":0.08938547,"width":0.014295213,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Retro 2026-05-12.mp4","depth":7,"bounds":{"left":0.087765954,"top":0.105347164,"width":0.049534574,"height":0.012769354},"on_screen":true,"value":"Retro 2026-05-12.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Today at 17:36","depth":7,"bounds":{"left":0.36569148,"top":0.105347164,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1,03 GB","depth":7,"bounds":{"left":0.4368351,"top":0.105347164,"width":0.017952127,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.4581117,"top":0.105347164,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Daily 2026-05-12.mp4","depth":7,"bounds":{"left":0.087765954,"top":0.121308856,"width":0.04886968,"height":0.012769354},"on_screen":true,"value":"Daily 2026-05-12.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Today at 10:13","depth":7,"bounds":{"left":0.36569148,"top":0.121308856,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1,02 GB","depth":7,"bounds":{"left":0.4368351,"top":0.121308856,"width":0.017952127,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.4581117,"top":0.121308856,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"PLanhat Petko interest event 2026-05-11.mp4","depth":7,"bounds":{"left":0.087765954,"top":0.13727055,"width":0.09607713,"height":0.012769354},"on_screen":true,"value":"PLanhat Petko interest event 2026-05-11.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Yesterday at 12:22","depth":7,"bounds":{"left":0.36569148,"top":0.13727055,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"144,5 MB","depth":7,"bounds":{"left":0.43351063,"top":0.13727055,"width":0.021276595,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.4581117,"top":0.13727055,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Daily 2026-05-11.mp4","depth":7,"bounds":{"left":0.087765954,"top":0.15323225,"width":0.048204787,"height":0.012769354},"on_screen":true,"value":"Daily 2026-05-11.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Yesterday at 10:02","depth":7,"bounds":{"left":0.36569148,"top":0.15323225,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"491,3 MB","depth":7,"bounds":{"left":0.43351063,"top":0.15323225,"width":0.021276595,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.4581117,"top":0.15323225,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Daily 2026-05-08.mp4","depth":7,"bounds":{"left":0.087765954,"top":0.16919394,"width":0.049534574,"height":0.012769354},"on_screen":true,"value":"Daily 2026-05-08.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"8 May 2026 at 10:22","depth":7,"bounds":{"left":0.36569148,"top":0.16919394,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1,37 GB","depth":7,"bounds":{"left":0.4368351,"top":0.16919394,"width":0.017952127,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.4581117,"top":0.16919394,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"}]...
|
-8075846093490464712
|
-6471475243605229611
|
click
|
accessibility
|
NULL
|
Favourites
jiminny
AirDrop
Recents
Applications
Do Favourites
jiminny
AirDrop
Recents
Applications
Documents
Downloads
lukas
iCloud
iCloud Drive
Sync folder
Locations
DXP4800PLUS-B5F
Eject
Network
Tags
CRM
Orange
Red
Yellow
Green
Blue
Purple
All Tags…
Name
Date Modified
Size
Kind
2026
Today at 17:39
--
Folder
Retro 2026-05-12.mp4
Today at 17:36
1,03 GB
MPEG-4 movie
Daily 2026-05-12.mp4
Today at 10:13
1,02 GB
MPEG-4 movie
PLanhat Petko interest event 2026-05-11.mp4
Yesterday at 12:22
144,5 MB
MPEG-4 movie
Daily 2026-05-11.mp4
Yesterday at 10:02
491,3 MB
MPEG-4 movie
Daily 2026-05-08.mp4
8 May 2026 at 10:22
1,37 GB
MPEG-4 movie...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
8694
|
388
|
23
|
2026-05-08T11:13:06.348408+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778238786348_m2.jpg...
|
Firefox
|
Jy 20493 smart instant nudge pre filtering by niko Jy 20493 smart instant nudge pre filtering by nikolaybiaivanov · Pull Request #12053 · jiminny/app — Work...
|
True
|
https://github.com/jiminny/app/pull/12053#pullrequ
|
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
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST [URL_WITH_CREDENTIALS]
Show options
nikolaybiaivanov commented yesterday
nikolaybiaivanov
nikolaybiaivanov
commented
yesterday
yesterday
JIRA: JY-XXXX
JIRA: JY-XXXX
Deployment notes:
Deployment notes:
None
Add or remove reactions
nikolaybiaivanov
nikolaybiaivanov
added
5
commits
yesterday
yesterday
@nikolaybiaivanov
JY-20493
JY-20493
| Smart match for nudges
| Smart match for nudges
7 / 10 checks OK
1825948
1825948
@nikolaybiaivanov
JY-20493
JY-20493
| Smart matching, add more cases
| Smart matching, add more cases
20 / 21 checks OK
9664393
9664393
@nikolaybiaivanov
JY-20493
JY-20493
| Change log type
| Change log type
20 / 21 checks OK
5fee7d8
5fee7d8
@nikolaybiaivanov
JY-20493
JY-20493
| Add tests
| Add tests
20 / 21 checks OK
91a6e0e
91a6e0e
@nikolaybiaivanov
JY-20493
JY-20493
| Add more tests
| Add more tests
21 / 21 checks OK
643587e
643587e
@nikolaybiaivanov
nikolaybiaivanov
nikolaybiaivanov
requested review from
LakyLak
LakyLak
and
yalokin-jiminny...
|
[{"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":"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.2237367,"top":0.08459697,"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":"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.23703457,"top":0.09577015,"width":0.4644282,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":4,"bounds":{"left":0.2237367,"top":0.11731844,"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.12849163,"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.15003991,"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.16121309,"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.18276137,"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.19393456,"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.21548285,"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.22665602,"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.2482043,"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.25937748,"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.28092578,"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.29209897,"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.31364724,"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.32482043,"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.3463687,"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.3575419,"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.3790902,"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.39026338,"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.41181165,"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.42298484,"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.4445331,"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.4557063,"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.4772546,"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.4884278,"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.509976,"width":0.07962101,"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":"Jy 20493 smart instant nudge pre filtering by nikolaybiaivanov · Pull Request #12053 · jiminny/app","depth":5,"bounds":{"left":0.23703457,"top":0.5211492,"width":0.17037898,"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.5171588,"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":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.2237367,"top":0.54269755,"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.55387074,"width":0.039228722,"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.57701516,"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":"Open 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":"AXLink","text":"Skip to content","depth":6,"on_screen":false,"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":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open menu","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Homepage (g then d)","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"jiminny","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"jiminny","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"app","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search or jump to…","depth":9,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Type","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":"AXStaticText","text":"to search","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chat with Copilot","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Open Copilot…","depth":9,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Create new...","depth":9,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"All issues(g then i)","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"All pull requests","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"All repositories","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"You have unread notifications(g then n)","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open user navigation menu","depth":9,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Repository navigation","depth":9,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Repository navigation","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pull requests (33)","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests","depth":14,"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":"AXStaticText","text":"33","depth":14,"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":"Agents","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Agents","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Actions","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Actions","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Wiki","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Wiki","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security and quality (2)","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security and quality","depth":14,"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":"AXStaticText","text":"2","depth":14,"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":"Insights","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Important update","depth":10,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Important update","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review this update","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review this update","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and manage your preferences in your","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub account settings","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub account settings","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dismiss banner","depth":9,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Jy 20493 smart instant nudge pre filtering #12053 Edit title","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jy 20493 smart instant nudge pre filtering","depth":14,"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":"AXStaticText","text":"12053","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit title","depth":14,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Unable to merge","depth":13,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Unable to merge","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Code","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":"Code","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Open","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"nikolaybiaivanov","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"nikolaybiaivanov","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 8 commits into","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":15,"on_screen":false,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20493-smart-instant-nudge-pre-filtering","depth":16,"on_screen":false,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20493-smart-instant-nudge-pre-filtering","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":16,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 723 additions & 24 deletions","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Conversation (10)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Conversation","depth":17,"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":"10","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":"AXRadioButton","text":"Commits (8)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Commits","depth":17,"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":"8","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":"AXRadioButton","text":"Checks (6)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checks","depth":17,"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":"6","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":"AXRadioButton","text":"Files changed (2)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Files changed","depth":17,"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":"2","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":"Open","depth":14,"bounds":{"left":0.4602726,"top":0.0726257,"width":0.011968086,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Jy 20493 smart instant nudge pre filtering #12053 nikolaybiaivanov wants to merge 8 commits into master from JY-20493-smart-instant-nudge-pre-filtering Copy head branch name to clipboard","depth":14,"bounds":{"left":0.4788896,"top":0.058260176,"width":0.24119017,"height":0.042298485},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"Jy 20493 smart instant nudge pre filtering","depth":16,"bounds":{"left":0.4788896,"top":0.05865922,"width":0.09541223,"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":"Jy 20493 smart instant nudge pre filtering","depth":17,"bounds":{"left":0.4788896,"top":0.06304868,"width":0.09541223,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":16,"bounds":{"left":0.57696146,"top":0.06304868,"width":0.0029920214,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12053","depth":16,"bounds":{"left":0.57995343,"top":0.06304868,"width":0.013464096,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"nikolaybiaivanov","depth":18,"bounds":{"left":0.4788896,"top":0.08339984,"width":0.032413565,"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":"nikolaybiaivanov","depth":19,"bounds":{"left":0.4788896,"top":0.08339984,"width":0.032413565,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 8 commits into","depth":18,"bounds":{"left":0.51263297,"top":0.08339984,"width":0.058011968,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":18,"bounds":{"left":0.57197475,"top":0.08180367,"width":0.018450798,"height":0.015163607},"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":19,"bounds":{"left":0.5739694,"top":0.083798885,"width":0.014461436,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":19,"bounds":{"left":0.59175533,"top":0.08339984,"width":0.008643617,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20493-smart-instant-nudge-pre-filtering","depth":19,"bounds":{"left":0.60172874,"top":0.08180367,"width":0.10472074,"height":0.015163607},"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20493-smart-instant-nudge-pre-filtering","depth":20,"bounds":{"left":0.6037234,"top":0.083798885,"width":0.10073138,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":19,"bounds":{"left":0.7077792,"top":0.07821229,"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":"AXHeading","text":"Conversation","depth":12,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"@nikolaybiaivanov","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show options","depth":15,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"nikolaybiaivanov commented yesterday","depth":14,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"nikolaybiaivanov","depth":16,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"nikolaybiaivanov","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"commented","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"yesterday","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"yesterday","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"JIRA: JY-XXXX","depth":16,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JIRA: JY-XXXX","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Deployment notes:","depth":16,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Deployment notes:","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"None","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Add or remove reactions","depth":16,"on_screen":false,"help_text":"","role_description":"summary","subrole":"AXSummary","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"nikolaybiaivanov","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"nikolaybiaivanov","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"added","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"commits","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"yesterday","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"yesterday","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"@nikolaybiaivanov","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"JY-20493","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20493","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"| Smart match for nudges","depth":14,"on_screen":false,"help_text":"JY-20493 | Smart match for nudges","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"| Smart match for nudges","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"7 / 10 checks OK","depth":14,"on_screen":false,"help_text":"","role_description":"summary","subrole":"AXSummary","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"1825948","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1825948","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"@nikolaybiaivanov","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"JY-20493","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20493","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"| Smart matching, add more cases","depth":14,"on_screen":false,"help_text":"JY-20493 | Smart matching, add more cases","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"| Smart matching, add more cases","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"20 / 21 checks OK","depth":14,"on_screen":false,"help_text":"","role_description":"summary","subrole":"AXSummary","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"9664393","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"9664393","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"@nikolaybiaivanov","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"JY-20493","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20493","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"| Change log type","depth":14,"on_screen":false,"help_text":"JY-20493 | Change log type","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"| Change log type","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"20 / 21 checks OK","depth":14,"on_screen":false,"help_text":"","role_description":"summary","subrole":"AXSummary","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"5fee7d8","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5fee7d8","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"@nikolaybiaivanov","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"JY-20493","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20493","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"| Add tests","depth":14,"on_screen":false,"help_text":"JY-20493 | Add tests","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"| Add tests","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"20 / 21 checks OK","depth":14,"on_screen":false,"help_text":"","role_description":"summary","subrole":"AXSummary","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"91a6e0e","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"91a6e0e","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"@nikolaybiaivanov","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"JY-20493","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20493","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"| Add more tests","depth":14,"on_screen":false,"help_text":"JY-20493 | Add more tests","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"| Add more tests","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"21 / 21 checks OK","depth":14,"on_screen":false,"help_text":"","role_description":"summary","subrole":"AXSummary","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"643587e","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"643587e","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"@nikolaybiaivanov","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"nikolaybiaivanov","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"nikolaybiaivanov","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"requested review from","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"LakyLak","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"LakyLak","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"yalokin-jiminny","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-8075264091639623202
|
-5601317287773837440
|
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
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST [URL_WITH_CREDENTIALS]
Show options
nikolaybiaivanov commented yesterday
nikolaybiaivanov
nikolaybiaivanov
commented
yesterday
yesterday
JIRA: JY-XXXX
JIRA: JY-XXXX
Deployment notes:
Deployment notes:
None
Add or remove reactions
nikolaybiaivanov
nikolaybiaivanov
added
5
commits
yesterday
yesterday
@nikolaybiaivanov
JY-20493
JY-20493
| Smart match for nudges
| Smart match for nudges
7 / 10 checks OK
1825948
1825948
@nikolaybiaivanov
JY-20493
JY-20493
| Smart matching, add more cases
| Smart matching, add more cases
20 / 21 checks OK
9664393
9664393
@nikolaybiaivanov
JY-20493
JY-20493
| Change log type
| Change log type
20 / 21 checks OK
5fee7d8
5fee7d8
@nikolaybiaivanov
JY-20493
JY-20493
| Add tests
| Add tests
20 / 21 checks OK
91a6e0e
91a6e0e
@nikolaybiaivanov
JY-20493
JY-20493
| Add more tests
| Add more tests
21 / 21 checks OK
643587e
643587e
@nikolaybiaivanov
nikolaybiaivanov
nikolaybiaivanov
requested review from
LakyLak
LakyLak
and
yalokin-jiminny...
|
8692
|
NULL
|
NULL
|
NULL
|
|
14730
|
656
|
2
|
2026-05-10T18:17:22.544297+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-10/1778 /Users/lukas/.screenpipe/data/data/2026-05-10/1778437042544_m2.jpg...
|
Claude
|
Claude
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Skip to content
Skip to content
Click to collapse
Skip to content
Skip to content
Click to collapse
⌘B
Drag to resize
Collapse sidebar
Search
Chat
Cowork
Code
New chat ⌘N
New chat
⌘N
Projects
Artifacts
Customize
Pinned
Bulgarian citizenship application process for EU residents
More options for Bulgarian citizenship application process for EU residents
Dawarich location tracking project
More options for Dawarich location tracking project
Recents
View all
Monthly expense tracking
More options for Monthly expense tracking
Exporting transaction data from Notion to finance hub
More options for Exporting transaction data from Notion to finance hub
Screenpipe sync script failing after recent migrations
More options for Screenpipe sync script failing after recent migrations
💬 How much have I spent for groc…
More options for 💬 How much have I spent for groc…
April 2026 spending by category
More options for April 2026 spending by category
Code diff review
More options for Code diff review
HubSpot rate limit implementation strategy
More options for HubSpot rate limit implementation strategy
Screenpipe retention policy code location
More options for Screenpipe retention policy code location
Viewing retention policy in screenpipe
More options for Viewing retention policy in screenpipe
Clean shot x video recording termination issue
More options for Clean shot x video recording termination issue
HubSpot rate limit handling with executeRequest
More options for HubSpot rate limit handling with executeRequest
Untitled
More options
💬 Screen pipe. Is there ability…
More options for 💬 Screen pipe. Is there ability…
SMB mount access inconsistency between Finder and iTerm
More options for SMB mount access inconsistency between Finder and iTerm
💬 What is the best switch I can…
More options for 💬 What is the best switch I can…
Permission denied on screenpipe volume
More options for Permission denied on screenpipe volume
Screenpipe sync database attachment error
More options for Screenpipe sync database attachment error
Last swimming outing with Dani
More options for Last swimming outing with Dani
Definition of incarcerated
More options for Definition of incarcerated
Chromecast remote volume buttons not working
More options for Chromecast remote volume buttons not working
Relaunch to update v1.6608.0
Relaunch to update
v1.6608.0
Lukas Pro
Get apps and extensions
Screenpipe sync script failing after recent migrations, rename chat
Screenpipe sync script failing after recent migrations
More options for Screenpipe sync script failing after recent migrations
Close
Claude is responding
You said: after recent updated in screenpipe (find out what are these) I am unable to run script.
You said: after recent updated in screenpipe (find out what are these) I am unable to run script.
Pasted Text, pasted, 353 lines
#!/bin/bash # screenpipe_sync.sh # Syncs Screenpipe SQLite data to a NAS archive database (append-only, no deletions). # Also copies the day's video/frame data folder to the NAS. # # Usage: # ./screenpipe_sync.sh # syncs yesterday (default) # ./screenpipe_sync.sh 2026-04-15 # sync
PASTED
after recent updated in screenpipe (find out what are these) I am unable to run script. (pasted) "lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ~/.screenpipe/screenpipe_sync.sh 2026-05-07
[2026-05-10 11:50:45] ========================================
[2026-05-10 11:50:45] Screenpipe sync starting for: 2026-05-07
[2026-05-10 11:50:45] ========================================
[+00m00s] ▶ Preflight checks
Source DB: OK (2.2G)
NAS mount: OK /Volumes/screenpipe
Archive DB: exists ( 10G)
Data dir: OK (266 files, 292M)
[+00m05s] ▶ Counting source rows for 2026-05-07
frames: 6262
elements: 623002
ui_events: 7412
ocr_text: 1670
meetings: 2
[+00m05s] ▶ Initialising tables, indexes, FTS
creating tables ✓ 0m00s
creating indexes ✓ 0m01s
creating FTS tables ✓ 0m00s
[+00m06s] ▶ Syncing data for 2026-05-07
video_chunks ✓ 0m01s
frames (6262 rows) ⠋ Parse error near line 3: table nas.frames has 24 columns but 30 values were supplied" There were some recent changes in migrations. Here are migrations form the begining of march (approx after I installed irt first time) 20260301000000 create elements table 2026-05-06 17:27:34 True 736637f38c6e0b5547f23c870ebbc3e87ef2d8d33b22ce73f7 ... 1302167
20260301100000 fts external content 2026-05-06 17:27:34 True 44ca0e5fc3b23c19aa09d7ac3fea48de604032d5feced2615c ... 2102875
20260301200000 drop ui monitoring 2026-05-06 17:27:34 True 9ab8a4d8c0d602b491ef1a6ff36076fd7b7c12c05848201682 ... 620375
20260306000000 delete empty transcriptions 2026-05-06 17:27:34 True 5f991a21d663157a2bce5cb9f0729f02181eef817aaef5a0b8 ... 166792
20260309000000 add cloud blob id 2026-05-06 17:27:34 True e1588e32884ec5660d11bbaa995d767fb2172bb9732ad22319 ... 1450542
20260310000000 create memories 2026-05-06 17:27:34 True 4fd07e878de1dd5b8d184e7bca9ee4e6b2480bbf39e5a68ff7 ... 1135416
20260311000000 drop unused tables 2026-05-06 17:27:34 True 3d9eb9d327a61c4055b31e22082cd045e00bd7a875cbdee86b ... 547625
20260312000000 consolidate search to frames full text 2026-05-06 17:27:34 True 5a7a31a359e9e93978d46ab4759fc8cd43898c0fd325d001b7 ... 3038250
20260312000001 drop dead fts tables 2026-05-06 17:27:34 True dd8264b96b4427f40b06ac60b813b77b6d055b24dd727212c5 ... 297250
20260312000002 drop accessibility tags 2026-05-06 17:27:34 True 672b2661f7e0fc8026f2eb6cc5d24935a15db4ed4982aeb973 ... 260167
20260315000000 add frame id to memories 2026-05-06 17:27:34 True f324ec7981134e647b6497126a2b6a7467e94d271d140d0d25 ... 642250
20260316000000 add elements activity summary index 2026-05-06 17:27:34 True 5b3f99a0d58fc73d62f240319d0718963364fdee1e3a7c4866 ... 265834
20260317000000 add elements automation props 2026-05-06 17:27:34 True 4bd132d263de143c7bb0dcf2e3b8074606c58c0f79e6091d13 ... 537750
20260318000000 add elements ref frame id 2026-05-06 17:27:34 True 33282b2c342e4743f096d1e3093146e243d97f392fe4df2cb5 ... 525250
20260319000000 add sync id indexes 2026-05-06 17:27:34 True 22c7a18c918cfcc458f05fdbfe2a0b2bb65a67ae9daeec6028 ... 407083
20260320000000 add note to meetings 2026-05-06 17:27:34 True cfa45b4c98e300c40cd36942839aa20528f47ae3e7b9c86751 ... 519625
20260324000000 drop ocr text delete trigger 2026-05-06 17:27:34 True 99f445308168fc88f993c43f8e884cc4dc7e41411c86b4d3e7 ... 182209
20260326000000 add session path to pipe executions 2026-05-06 17:27:34 True 5aa266dfcd7b741a18dd3ffb6b0ca3caf2e569959074cbc3ff ... 549583
20260411000000 add elements ref frame id index 2026-05-06 17:27:34 True 378589322920e74980ea48c6b44c916cd488e47a8f6172161e ... 232083
20260415000000 frames fts external content 2026-05-06 17:27:34 True 3fdac70da2fd44bca3c3717768b57c4cbee743451b73f13de9 ... 1259250
20260423000000 add speaker id indexes 2026-05-06 17:27:34 True 80e8e0cf144ee620c81b3796196ca22b8e34f9c152ca2ffe8f ... 398709
20260429000000 add evicted at to chunks 2026-05-06 17:27:34 True 180b1d44305df17620929a69ecce60fa3ce0148905adf19ff7 ... 963833
20260502000000 add elements on screen 2026-05-06 17:27:34 True 2cf51a077a75ef32e4e1d722092053ce919bdeee151d3d91fb ... 644500
20260504120000 add document path column 2026-05-06 17:27:34 True d84f7127e1647984eeb1f89e8dffd0918525f128e4608d323f ... 593042
20260506120000 add memories sync columns 2026-05-07 06:45:22 True 800beaaa228c7fbd88fe367dc5b357adb72a3a0635da5a30f4 ... 1777417
20260501000000 add redacted columns 2026-05-08 06:25:45 True 2a4cd6714a2322ccf8f2af6084af5a05e40f460c44c1aaf874 ... 795120667
20260503000000 add frames image redacted 2026-05-08 06:25:45 True . It worked up to the point where I attemtped to remove it and install again since the retention policy doesn't clear old data and it was to big. I am basically moving data to nas and query it form there. mac is for capture only or lets say one week query using claude code. THe main consumer and interface is on nas. How to make it work so new changes won't messup my setup. Seems like I removed the whole folder it was working find runnign with @letest even I may be wrong.
Show more
11:58
Edit
Copy
Claude responded: Looking at this carefully, the error tells the whole story:
Claude responded: Looking at this carefully, the error tells the whole story:
Pinpointing schema mismatches from recent PII redaction migrations
Pinpointing schema mismatches from recent PII redaction migrations
Looking at this carefully, the error tells the whole story:
Copy to clipboard
table nas.frames has 24 columns but 30 values were supplied
Your source DB got 6 new columns from recent migrations, but the NAS archive was created earlier with the old schema.
CREATE TABLE IF NOT EXISTS
is a no-op when the table exists, so the NAS schema is frozen at whatever it was when first created. Then
INSERT ... SELECT *
does positional mapping, which blows up the moment column counts diverge.
Let me verify the recent screenpipe changes and then fix this properly.
Diagnosed schema drift, architected resilient migration strategy
Diagnosed schema drift, architected resilient migration strategy
What's happening
What's happening
The error is schema drift, not a screenpipe bug. Your source DB grew 6 columns from these migrations (most landed late April / early May with the PII work):
20260429000000 add evicted at to chunks
→
video_chunks.evicted_at
20260502000000 add elements on screen
→
elements.on_screen
20260504120000 add document path column
→
frames.document_path
20260501000000 add redacted columns
→ redacted columns on frames/ocr_text/elements (this is the big one — accompanies the new
screenpipe/pii-redactor
model)
20260503000000 add frames image redacted
→
frames.image_redacted_path
20260506120000 add memories sync columns
→ memories table
Your NAS
archive.db
was created before these landed.
CREATE TABLE IF NOT EXISTS
is a no-op on existing tables, so the NAS schema froze. Then
INSERT INTO nas.frames SELECT * FROM main.frames
does
positional
mapping → 30 source values into a 24-column NAS table → parse error.
You weren't wrong about
npx screenpipe@latest
working: removing the folder gave you a fresh local DB with the new schema, and querying still works because everything is on one schema. The mismatch only surfaces when you try to merge old + new schemas via the sync.
The fix
The fix
Two changes make this future-proof:
ensure_columns
— before each insert, diff source vs NAS columns and run
ALTER TABLE ADD COLUMN
for any new ones. SQLite handles this as a metadata-only op, so it's instant even on your 10G archive.
Explicit column lists in INSERT
— never
SELECT *
again. Build the column list dynamically from
PRAGMA table_info(<table>)
and use
INSERT INTO t (cols) SELECT cols FROM ...
. Now positional drift is structurally impossible.
Bonus: dropped columns in future migrations will also be handled gracefully — the archive keeps the column with NULLs for new rows, no errors.
Let me write the updated script.
Created a file, ran a command, read a file
Created a file, ran a command, read a file
What changed in the script
What changed in the script
Three additions, everything else preserved:
Schema helpers
(
table_columns_with_types
,
table_columns
,
table_exists
,
ensure_columns
,
build_col_list
) — pure bash + sqlite3 PRAGMA, no extra deps.
New "Reconciling NAS schema with source" step
— runs after
CREATE TABLE IF NOT EXISTS
, before indexes/FTS/inserts. For each table in
SYNC_TABLES
, it diffs source columns against NAS and
ALTER TABLE ADD COLUMN
s the missing ones. Output looks like:
Copy to clipboard
schema: frames ✓ added 4: cloud_blob_id document_path image_redacted_path text_redacted
schema: elements ✓ added 2: on_screen text_redacted
schema: video_chunks ✓ added 1: evicted_at
Explicit column lists in every INSERT
—
FRAMES_COLS=$(build_col_list frames)
builds
"id","timestamp","app_name",...
from source
PRAGMA table_info
, and the inserts use
INSERT INTO nas.t (cols) SELECT cols FROM main.t
. No more positional mapping. Column names are double-quoted so any future hyphens or reserved-word columns won't break parsing.
What to expect on the next run
What to expect on the next run
First run after dropping it in: the "Reconciling NAS schema with source" step will print the missing columns it adds to your existing 10G archive (4 on
frames
, plus a few on
elements
/
video_chunks
/
ocr_text
). Each
ALTER TABLE ADD COLUMN
is a metadata-only op in SQLite — no table rewrite, no VACUUM needed, total cost should be sub-second even on the 10G file. Then 2026-05-07 will sync normally.
After that, when Screenpipe ships the next migration, your sync just picks up the new columns automatically. No more breakage.
One thing worth knowing
One thing worth knowing
If Screenpipe ever
drops
a column in source (rare but possible — they did
drop ui monitoring
and
drop dead fts tables
earlier), the NAS will still have it, and
build_col_list
(sourced from
main
) won't reference it. New rows will have NULL for the orphaned column, old rows keep their data. That's the right archival behavior — but if you ever want to actually drop those orphan columns from NAS, that's a manual
ALTER TABLE ... DROP COLUMN
which SQLite has supported since 3.35 (your macOS Tahoe ships 3.43+, and your NAS Docker SQLite is fine).
View Screenpipe sync
Screenpipe sync
SH
Open Screenpipe sync
Open in iTerm
Copy
Give positive feedback
Give negative feedback
You said: ok but given the changes introduced is there something I may actually use
You said: ok but given the changes introduced is there something I may actually use
ok but given the changes introduced is there something I may actually use
12:06
Edit
Copy
Claude responded: Good question.
Claude responded: Good question.
Cataloging PII redactor capabilities and security categories
Cataloging PII redactor capabilities and security categories
Good question. Let me look at what these new columns actually do and which ones map to your setup, since not all of them are equal value for you.
Evaluated four practical database columns for his specific workflow needs
Evaluated four practical database columns for his specific workflow needs
Yeah, three of them are genuinely useful for your setup. The rest are cloud-sync plumbing you can ignore.
frames.document_path — most useful for you
frames.document_path
— most useful for you
Captures the path of the document/file open at frame time. This is a meaningful upgrade over relying on
app_name
+
window_name
for IDE work.
Concrete uses given your stack:
Daily activity summary
: instead of "spent 2h in PhpStorm", you can group by
document_path
and get "spent 2h in
app/Http/Controllers/ReportsController.php
" — directly tied to the JY-20458 work.
Ticket correlation
: branch names contain ticket IDs in PhpStorm window titles, but file paths are cleaner. Query
WHERE document_path LIKE '%/reports/%'
to slice by feature area.
Replaces some of the
LIKE '%JY-%'
fishing
: your hyphenated-token issue with FTS5 mostly comes up in OCR text. For "what was I working on",
document_path
skips OCR entirely.
Worth adding an index on the NAS:
Copy to clipboard
sql
CREATE
INDEX
IF
NOT
EXISTS
idx_frames_document_path
ON
frames
(
document_path
)
WHERE
document_path
IS
NOT
NULL
;
elements.on_screen — directly useful for the meeting detector
elements.on_screen
— directly useful for the meeting detector
This is a boolean for whether the element was actually visible (vs. in the accessibility tree but scrolled off / occluded / behind a collapsed panel).
For your
meeting-detector
pipeline:
Zoom's accessibility tree exposes
everyone
on the call, including names in collapsed roster panels. Adding
WHERE on_screen = 1
cuts the participant detector down to people whose name tile was actually rendered — much closer to "who was visible during this segment".
For daily summaries: weights time-on-element by visibility, so reading vs. having-a-tab-open look different.
Cheap to add, big signal-to-noise win.
PII redaction columns (text_redacted etc.) — useful but with caveats
PII redaction columns (
text_redacted
etc.) — useful but with caveats
The model behind these is
screenpipe/pii-redactor
, fine-tuned for accessibility trees, OCR'd screen text, and computer-use traces. Detects 12 categories including a
secret
class that catches passwords, API keys, JWTs, DB connection strings, and PRIVATE-KEY markers — exactly the stuff that leaks into your captures during Laravel/Salesforce/HubSpot dev work.
For your setup, this maps well because:
The NAS archive is the consumer, queried by Claude Code agentically. Pointing those queries at
text_redacted
rather than
text
reduces the blast radius if a prompt or tool result ends up somewhere unexpected.
Your Mac captures Jiminny customer data on every call. Redacted text is safer for archival queries that don't need exact content (which is most of them).
Caveats worth knowing before flipping it on:
Probably opt-in.
Migrations only added the columns; redaction itself almost certainly needs a flag (worth checking
screenpipe record --help
for something like
--enable-pii-redaction
). Without enabling, the columns just stay NULL.
Over-redacts on short strings
: ~8% on accessibility/window titles, ~16% on long-form. Bulgarian names + Slovak surnames in your genealogy notes will likely trigger false positives. Keep the unredacted
text
column for cases where you need ground truth.
Model license is CC BY-NC 4.0
— non-commercial only, so not suitable for anything Jiminny-business related; fine for personal use.
Practical pattern: query
text_redacted
by default, fall back to
text
only when you explicitly need the raw value.
video_chunks.evicted_at — minor diagnostic value
video_chunks.evicted_at
— minor diagnostic value
When the local retention policy prunes a chunk, this stamps the time. Given your 7-day retention + nightly sync to NAS, you could add a preflight check that warns if a chunk got evicted before its frames were synced (would mean you have frame metadata pointing to deleted video). Realistically your nightly sync at 3am is well inside the 7-day window, so this is more "nice diagnostic" than "must-use".
Skip these
Skip these
frames.cloud_blob_id
,
memories sync columns
— for the optional E2EE cloud sync feature. You self-host, you don't need them. Stays NULL.
If you want, I can draft a small SQL migration for the NAS-side indexes (
document_path
,
on_screen
) and a tweaked version of your daily-activity-summary Claude Code prompt that uses
document_path
for grouping. Both are short.
Copy
Give positive feedback
Give negative feedback
You said: yes do it.
You said: yes do it.
yes do it. I want frames.document_path and elements.on_screen. Do I need to add it to the script as well (if running for the first time on new machine). But for archive.db on nas I need to add it now. Also what would be the effect on older data if don't have data there?
12:16
Edit
Copy
Claude responded: Three deliverables coming up: the immediate NAS migration, the script patch, and an updated daily-summary prompt.
Claude responded: Three deliverables coming up: the immediate NAS migration, the script patch, and an updated daily-summary prompt.
Architected migration strategy, index optimization, and data continuity implications
Architected migration strategy, index optimization, and data continuity implications
Three deliverables coming up: the immediate NAS migration, the script patch, and an updated daily-summary prompt. Plus a clean answer on the older-data question.
What happens to older data
What happens to older data
Both columns will be
NULL
for every row that's already in the archive. Screenpipe only started populating them on the migration dates (
document_path
from May 4,
on_screen
from May 2 in source — for your archive, from whenever you first sync data captured after those dates).
Practical implications:
WHERE document_path = 'foo'
— silently skips all old rows. Same for
WHERE document_path IS NOT NULL
.
WHERE on_screen = 1
— silently skips all old element rows (NULL is neither 1 nor 0).
WHERE on_screen = 0
— also skips them (NULL ≠ 0).
So queries using these columns are implicitly forward-looking.
No backfill is possible
— screenpipe didn't capture this signal at the time, the data simply doesn't exist for those moments. If you need a hybrid query (use
document_path
when present, fall back to
window_name
for older data), use
COALESCE(document_path, window_name)
or an explicit branching CASE.
The partial indexes (with
WHERE ... IS NOT NULL
) handle this elegantly — they ignore old rows entirely, so they stay small and only grow with new data.
Run this now against the NAS archive
Run this now against the NAS archive
Two partial indexes — they index only the rows that actually have data, so they're effectively instant on your 10G archive (currently zero qualifying rows):
Copy to clipboard
bash
sqlite3 /Volumes/screenpipe/archive.db
<<
'SQL'
CREATE INDEX IF NOT EXISTS idx_frames_document_path
ON frames(document_path) WHERE document_path IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_elements_onscreen_frame
ON elements(frame_id) WHERE on_screen = 1 AND text IS NOT NULL;
SQL
Note on the second index: a plain index on
on_screen
alone is useless (boolean = 2 distinct values, low selectivity). The composite-partial form is what you actually want — it pre-filters to visible elements with text, anchored on
frame_id
for join performance, and complements rather than replaces your existing
idx_elements_frame_src_role
.
Yes, add to the script for fresh installs
Yes, add to the script for fresh installs
In the "creating indexes" heredoc in
screenpipe_sync.sh
, add these two lines alongside the existing ones:
Edited a file, ran a command
Edited a file, ran a command
On a fresh machine, the flow is:
CREATE TABLE IF NOT EXISTS ... AS SELECT * FROM main.frames WHERE 0
clones the source schema (so the columns appear automatically), and then
CREATE INDEX IF NOT EXISTS
builds the partial indexes — both effectively no-ops since fresh data populates as it syncs. So yes, the patched script handles fresh installs correctly without further intervention.
Updated daily activity summary prompt
Updated daily activity summary prompt
This uses both new columns, falls back gracefully for old data, and keeps the Europe/Sofia timezone conversion you already have.
Created a file, read a file
Created a file, read a file
Summary of what to do, in order
Summary of what to do, in order
Now
: run the two
CREATE INDEX
statements above against
/Volumes/screenpipe/archive.db
(sub-second since both are partial indexes on currently-empty conditions).
Replace your existing script
with the patched
screenpipe_sync.sh
— it has both the schema-drift handling from before and the two new indexes baked in.
Run a test sync
for 2026-05-07 — should now succeed, with the
Reconciling NAS schema with source
step adding the missing columns to your existing 10G archive in one shot.
From May 7 forward
, queries against the NAS will see populated
document_path
and
on_screen
data. The new daily prompt will start producing useful file-level breakdowns; for backfilled days where those columns are NULL, it falls back to
window_name
grouping and notes the limitation.
One side-thought for your meeting detector: when you next iterate on
pipeline.py
, swap the participant scan to
WHERE on_screen = 1 OR on_screen IS NULL
— old data still works, new data gets noise filtering for free. Same one-line change.
View Daily activity prompt
Daily activity prompt
Document
·
MD
Open Daily activity prompt
Open in Windsurf
View Screenpipe sync
Screenpipe sync
SH
Open Screenpipe sync
Open in iTerm
Download all
Download all
Copy
Give positive feedback
Give negative feedback
You said: I added lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.
You said: I added lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.
I added lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ll
total 4612768
drwxr-xr-x 16 lukas staff 512 10 May 13:06 .
drwx------+ 94 lukas staff 3008 8 May 22:00 ..
-rw-r--r--@ 1 lukas staff 6148 10 May 11:39 .DS_Store
drwxr-xr-x 19 lukas staff 608 10 May 11:39 data
-rw-r--r--@ 1 lukas staff 2360483840 10 May 11:50 db.sqlite
-rw-r--r--@ 1 lukas staff 32768 10 May 11:50 db.sqlite-shm
-rw-r--r--@ 1 lukas staff 0 10 May 11:50 db.sqlite-wal
drwxr-xr-x 9 lukas staff 288 10 May 11:39 pipes
-rw-r--r-- 1 lukas staff 28408 6 May 21:02 screenpipe.2026-05-06.0.log
-rw-r--r-- 1 lukas staff 566164 7 May 21:50 screenpipe.2026-05-07.0.log
-rw-r--r-- 1 lukas staff 382102 8 May 22:20 screenpipe.2026-05-08.0.log
-rw-r--r-- 1 lukas staff 167023 9 May 23:04 screenpipe.2026-05-09.0.log
-rw-r--r-- 1 lukas staff 7751 10 May 11:37 screenpipe.2026-05-10.0.log
-rwxr-xr-x@ 1 lukas staff 14994 6 May 20:26 screenpipe_sync.sh
-rw-r--r-- 1 lukas staff 19713 10 May 13:06 screenpipe_sync_updated.sh
-rw-r--r--@ 1 lukas staff 4648 10 May 11:50 sync.log screepipe_sync_updated.sh. How to add it the rights to execute? Where is Daily activity prompt used? Also maybe lets include copying of logs to nas (like screenpipe.2026-05-10.0.log)
Show more
13:08
Edit
Copy
Claude responded: Three quick fixes.
Claude responded: Three quick fixes.
Orchestrated solutions for permissions, prompt usage, and log synchronization
Orchestrated solutions for permissions, prompt usage, and log synchronization
Three quick fixes. Let me handle them in order.
1. Execute permissions + replace the old script
1. Execute permissions + replace the old script
Your existing script at
screenpipe_sync.sh
is what cron calls (if you have cron set up). Cleanest path is to back up the old one, then move the updated version into its place — keeps cron working without touching crontab:
Copy to clipboard
bash
cd
~/.screenpipe
chmod
+x screenpipe_sync_updated.sh
mv
screenpipe_sync.sh screenpipe_sync.sh.bak
mv
screenpipe_sync_updated.sh screenpipe_sync.sh
If you'd rather keep both around (e.g., to A/B test for a day), just do
chmod +x screenpipe_sync_updated.sh
and run it directly until you're happy, then swap.
2. Where the daily activity prompt lives
2. Where the daily activity prompt lives
It's a Claude Code prompt template — input you feed to
claude
to generate the daily summary. A few placement options, in increasing order of integration:
Option A — manual invocation (simplest):
Save to
~/.screenpipe/daily_activity_prompt.md
, then:
Copy to clipboard
bash
TARGET_DATE
=
2026
-05-09
DB_PATH
=
/Volumes/screenpipe/archive.db
sed
-e
"s|\
$TARGET_DATE
|
$TARGET_DATE
|g"
-e
"s|\
$DB_PATH
|
$DB_PATH
|g"
\
~/.screenpipe/daily_activity_prompt.md
|
claude
Option B — Claude Code custom slash command (most ergonomic):
Claude Code reads
~/.claude/commands/*.md
as custom slash commands. Save the prompt there and invoke it as
/daily
from a Claude Code session:
Copy to clipboard
bash
mkdir
-p ~/.claude/commands
cp
~/.screenpipe/daily_activity_prompt.md ~/.claude/commands/daily.md
Then in Claude Code:
/daily 2026-05-09
and Claude will run the SQL queries via its bash tool against the DB and produce the markdown.
Option C — wrapper script:
A small
~/.screenpipe/daily.sh
that takes a date arg and pipes the substituted prompt to
claude
. I can write this if you want — let me know which path you prefer (most likely B given how you work).
3. Adding log copying to the sync
3. Adding log copying to the sync
Patching the script now. New section copies
screenpipe.YYYY-MM-DD.*.log
to
$NAS_MOUNT/logs/
. Flat directory rather than nested under each day, so you can
grep
across days easily.
Edited a file, ran a command, read a file
Edited a file, ran a command, read a file
Notes on the log copy behavior
Notes on the log copy behavior
Glob handles rotation
:
screenpipe.$TARGET_DATE.*.log
catches any future
.1.log
,
.2.log
files if Screenpipe ever rotates within a day.
nullglob
ensures we don't get a literal pattern when there's no match.
No
--ignore-existing
: when you sync
today
, the log is still being written. Default rsync (
-a
) uses size+mtime to detect changes, so the next sync run will refresh it with the latest content.
Flat
logs/
directory on NAS
: easier to
grep -h "ERROR" logs/*.log
across days than walking nested per-date folders. If you'd rather have it under the date dir alongside frames, the change is one path swap.
After running the new sync once, you should see:
Copy to clipboard...
|
[{"role":"AXLink","text":& [{"role":"AXLink","text":"Skip to content","depth":14,"bounds":{"left":0.0023271276,"top":0.025538707,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Skip to content","depth":15,"bounds":{"left":0.0023271276,"top":0.026336791,"width":0.030917553,"height":0.013567438},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.0023271276,"top":0.027134877,"width":0.0026595744,"height":0.012769354}},{"char_start":1,"char_count":14,"bounds":{"left":0.004986702,"top":0.027134877,"width":0.02825798,"height":0.012769354}}],"role_description":"text"},{"role":"AXStaticText","text":"Click to collapse","depth":16,"bounds":{"left":0.10239362,"top":0.63846767,"width":0.030585106,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10239362,"top":0.63846767,"width":0.0029920214,"height":0.011971269}},{"char_start":1,"char_count":16,"bounds":{"left":0.10538564,"top":0.63846767,"width":0.027925532,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"⌘B","depth":16,"bounds":{"left":0.1349734,"top":0.63846767,"width":0.0063164895,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drag to resize","depth":16,"bounds":{"left":0.10239362,"top":0.65043896,"width":0.025930852,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10239362,"top":0.65043896,"width":0.0029920214,"height":0.011971269}},{"char_start":1,"char_count":13,"bounds":{"left":0.10538564,"top":0.65043896,"width":0.022938829,"height":0.011971269}}],"role_description":"text"},{"role":"AXButton","text":"Collapse sidebar","depth":15,"bounds":{"left":0.030585106,"top":0.02952913,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search","depth":15,"bounds":{"left":0.03856383,"top":0.02952913,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Chat","depth":16,"bounds":{"left":0.005984043,"top":0.06304868,"width":0.026263298,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cowork","depth":16,"bounds":{"left":0.032579787,"top":0.06304868,"width":0.031914894,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code","depth":16,"bounds":{"left":0.065159574,"top":0.06304868,"width":0.027260639,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New chat ⌘N","depth":15,"bounds":{"left":0.005319149,"top":0.0933759,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"New chat","depth":16,"bounds":{"left":0.015292553,"top":0.096568234,"width":0.019281914,"height":0.013567438},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.015292553,"top":0.09736632,"width":0.0033244682,"height":0.013567438}},{"char_start":1,"char_count":7,"bounds":{"left":0.01861702,"top":0.09736632,"width":0.015957447,"height":0.013567438}}],"role_description":"text"},{"role":"AXStaticText","text":"⌘N","depth":17,"bounds":{"left":0.084109046,"top":0.09736632,"width":0.006981383,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Projects","depth":15,"bounds":{"left":0.005319149,"top":0.11412609,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Artifacts","depth":15,"bounds":{"left":0.005319149,"top":0.1348763,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Customize","depth":15,"bounds":{"left":0.005319149,"top":0.15562649,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Pinned","depth":16,"bounds":{"left":0.00731383,"top":0.19553073,"width":0.08510638,"height":0.012769354},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"Bulgarian citizenship application process for EU residents","depth":18,"bounds":{"left":0.005319149,"top":0.2122905,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Bulgarian citizenship application process for EU residents","depth":19,"bounds":{"left":0.08577128,"top":0.21548285,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Dawarich location tracking project","depth":18,"bounds":{"left":0.005319149,"top":0.23383878,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Dawarich location tracking project","depth":19,"bounds":{"left":0.08577128,"top":0.23703113,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Recents","depth":16,"bounds":{"left":0.00731383,"top":0.264166,"width":0.064494684,"height":0.012769354},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"View all","depth":16,"bounds":{"left":0.0731383,"top":0.264166,"width":0.019281914,"height":0.012769354},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Monthly expense tracking","depth":18,"bounds":{"left":0.005319149,"top":0.28092578,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Monthly expense tracking","depth":19,"bounds":{"left":0.08577128,"top":0.28411812,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Exporting transaction data from Notion to finance hub","depth":18,"bounds":{"left":0.005319149,"top":0.30247405,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Exporting transaction data from Notion to finance hub","depth":19,"bounds":{"left":0.08577128,"top":0.3056664,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Screenpipe sync script failing after recent migrations","depth":18,"bounds":{"left":0.005319149,"top":0.32402235,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Screenpipe sync script failing after recent migrations","depth":19,"bounds":{"left":0.08577128,"top":0.3272147,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"💬 How much have I spent for groc…","depth":18,"bounds":{"left":0.005319149,"top":0.34557062,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for 💬 How much have I spent for groc…","depth":19,"bounds":{"left":0.08577128,"top":0.34876296,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"April 2026 spending by category","depth":18,"bounds":{"left":0.005319149,"top":0.36711892,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for April 2026 spending by category","depth":19,"bounds":{"left":0.08577128,"top":0.37031126,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code diff review","depth":18,"bounds":{"left":0.005319149,"top":0.3886672,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Code diff review","depth":19,"bounds":{"left":0.08577128,"top":0.39185953,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HubSpot rate limit implementation strategy","depth":18,"bounds":{"left":0.005319149,"top":0.4102155,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for HubSpot rate limit implementation strategy","depth":19,"bounds":{"left":0.08577128,"top":0.41340783,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Screenpipe retention policy code location","depth":18,"bounds":{"left":0.005319149,"top":0.43176377,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Screenpipe retention policy code location","depth":19,"bounds":{"left":0.08577128,"top":0.4349561,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Viewing retention policy in screenpipe","depth":18,"bounds":{"left":0.005319149,"top":0.45331204,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Viewing retention policy in screenpipe","depth":19,"bounds":{"left":0.08577128,"top":0.45650437,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Clean shot x video recording termination issue","depth":18,"bounds":{"left":0.005319149,"top":0.47486034,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Clean shot x video recording termination issue","depth":19,"bounds":{"left":0.08577128,"top":0.47805268,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HubSpot rate limit handling with executeRequest","depth":18,"bounds":{"left":0.005319149,"top":0.4964086,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for HubSpot rate limit handling with executeRequest","depth":19,"bounds":{"left":0.08577128,"top":0.49960095,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Untitled","depth":18,"bounds":{"left":0.005319149,"top":0.5179569,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options","depth":19,"bounds":{"left":0.08577128,"top":0.5211492,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"💬 Screen pipe. Is there ability…","depth":18,"bounds":{"left":0.005319149,"top":0.5395052,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for 💬 Screen pipe. Is there ability…","depth":19,"bounds":{"left":0.08577128,"top":0.54269755,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"SMB mount access inconsistency between Finder and iTerm","depth":18,"bounds":{"left":0.005319149,"top":0.56105345,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for SMB mount access inconsistency between Finder and iTerm","depth":19,"bounds":{"left":0.08577128,"top":0.5642458,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"💬 What is the best switch I can…","depth":18,"bounds":{"left":0.005319149,"top":0.5826017,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for 💬 What is the best switch I can…","depth":19,"bounds":{"left":0.08577128,"top":0.5857941,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Permission denied on screenpipe volume","depth":18,"bounds":{"left":0.005319149,"top":0.60415006,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Permission denied on screenpipe volume","depth":19,"bounds":{"left":0.08577128,"top":0.60734236,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Screenpipe sync database attachment error","depth":18,"bounds":{"left":0.005319149,"top":0.6256983,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Screenpipe sync database attachment error","depth":19,"bounds":{"left":0.08577128,"top":0.62889063,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Last swimming outing with Dani","depth":18,"bounds":{"left":0.005319149,"top":0.6472466,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Last swimming outing with Dani","depth":19,"bounds":{"left":0.08577128,"top":0.65043896,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Definition of incarcerated","depth":18,"bounds":{"left":0.005319149,"top":0.6687949,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Definition of incarcerated","depth":19,"bounds":{"left":0.08577128,"top":0.67198724,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Chromecast remote volume buttons not working","depth":18,"bounds":{"left":0.005319149,"top":0.6903432,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Chromecast remote volume buttons not working","depth":19,"bounds":{"left":0.08577128,"top":0.6935355,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Relaunch to update v1.6608.0","depth":15,"bounds":{"left":0.005319149,"top":0.9169992,"width":0.087765954,"height":0.04309657},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Relaunch to update","depth":16,"bounds":{"left":0.023271276,"top":0.92498004,"width":0.043218084,"height":0.013567438},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.023603724,"top":0.92498004,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":17,"bounds":{"left":0.026595745,"top":0.92498004,"width":0.039893616,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"v1.6608.0","depth":16,"bounds":{"left":0.023271276,"top":0.94094175,"width":0.015957447,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.023603724,"top":0.94094175,"width":0.0019946808,"height":0.011173184}},{"char_start":1,"char_count":8,"bounds":{"left":0.025598405,"top":0.94094175,"width":0.013630319,"height":0.011173184}}],"role_description":"text"},{"role":"AXPopUpButton","text":"Lukas Pro","depth":15,"bounds":{"left":0.005319149,"top":0.9696728,"width":0.038231384,"height":0.01915403},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Get apps and extensions","depth":15,"bounds":{"left":0.08510638,"top":0.9696728,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Screenpipe sync script failing after recent migrations, rename chat","depth":19,"bounds":{"left":0.10239362,"top":0.02793296,"width":0.119015954,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Screenpipe sync script failing after recent migrations","depth":21,"bounds":{"left":0.10372341,"top":0.031923383,"width":0.11635638,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.031923383,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":53,"bounds":{"left":0.106715426,"top":0.031923383,"width":0.113696806,"height":0.014365523}}],"role_description":"text"},{"role":"AXPopUpButton","text":"More options for Screenpipe sync script failing after recent migrations","depth":19,"bounds":{"left":0.22174202,"top":0.02793296,"width":0.006981383,"height":0.022346368},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":21,"bounds":{"left":0.28224733,"top":0.026336791,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Claude is responding","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"You said: after recent updated in screenpipe (find out what are these) I am unable to run script.","depth":20,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"You said: after recent updated in screenpipe (find out what are these) I am unable to run script.","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Pasted Text, pasted, 353 lines","depth":21,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"#!/bin/bash # screenpipe_sync.sh # Syncs Screenpipe SQLite data to a NAS archive database (append-only, no deletions). # Also copies the day's video/frame data folder to the NAS. # # Usage: # ./screenpipe_sync.sh # syncs yesterday (default) # ./screenpipe_sync.sh 2026-04-15 # sync","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PASTED","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"after recent updated in screenpipe (find out what are these) I am unable to run script. (pasted) \"lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ~/.screenpipe/screenpipe_sync.sh 2026-05-07\n[2026-05-10 11:50:45] ========================================\n[2026-05-10 11:50:45] Screenpipe sync starting for: 2026-05-07\n[2026-05-10 11:50:45] ========================================\n[+00m00s] ▶ Preflight checks\n Source DB: OK (2.2G)\n NAS mount: OK /Volumes/screenpipe\n Archive DB: exists ( 10G)\n Data dir: OK (266 files, 292M)\n[+00m05s] ▶ Counting source rows for 2026-05-07\n frames: 6262\n elements: 623002\n ui_events: 7412\n ocr_text: 1670\n meetings: 2\n[+00m05s] ▶ Initialising tables, indexes, FTS\n creating tables ✓ 0m00s\n creating indexes ✓ 0m01s\n creating FTS tables ✓ 0m00s\n[+00m06s] ▶ Syncing data for 2026-05-07\n video_chunks ✓ 0m01s\n frames (6262 rows) ⠋ Parse error near line 3: table nas.frames has 24 columns but 30 values were supplied\" There were some recent changes in migrations. Here are migrations form the begining of march (approx after I installed irt first time) 20260301000000 create elements table 2026-05-06 17:27:34 True 736637f38c6e0b5547f23c870ebbc3e87ef2d8d33b22ce73f7 ... 1302167\n20260301100000 fts external content 2026-05-06 17:27:34 True 44ca0e5fc3b23c19aa09d7ac3fea48de604032d5feced2615c ... 2102875\n20260301200000 drop ui monitoring 2026-05-06 17:27:34 True 9ab8a4d8c0d602b491ef1a6ff36076fd7b7c12c05848201682 ... 620375\n20260306000000 delete empty transcriptions 2026-05-06 17:27:34 True 5f991a21d663157a2bce5cb9f0729f02181eef817aaef5a0b8 ... 166792\n20260309000000 add cloud blob id 2026-05-06 17:27:34 True e1588e32884ec5660d11bbaa995d767fb2172bb9732ad22319 ... 1450542\n20260310000000 create memories 2026-05-06 17:27:34 True 4fd07e878de1dd5b8d184e7bca9ee4e6b2480bbf39e5a68ff7 ... 1135416\n20260311000000 drop unused tables 2026-05-06 17:27:34 True 3d9eb9d327a61c4055b31e22082cd045e00bd7a875cbdee86b ... 547625\n20260312000000 consolidate search to frames full text 2026-05-06 17:27:34 True 5a7a31a359e9e93978d46ab4759fc8cd43898c0fd325d001b7 ... 3038250\n20260312000001 drop dead fts tables 2026-05-06 17:27:34 True dd8264b96b4427f40b06ac60b813b77b6d055b24dd727212c5 ... 297250\n20260312000002 drop accessibility tags 2026-05-06 17:27:34 True 672b2661f7e0fc8026f2eb6cc5d24935a15db4ed4982aeb973 ... 260167\n20260315000000 add frame id to memories 2026-05-06 17:27:34 True f324ec7981134e647b6497126a2b6a7467e94d271d140d0d25 ... 642250\n20260316000000 add elements activity summary index 2026-05-06 17:27:34 True 5b3f99a0d58fc73d62f240319d0718963364fdee1e3a7c4866 ... 265834\n20260317000000 add elements automation props 2026-05-06 17:27:34 True 4bd132d263de143c7bb0dcf2e3b8074606c58c0f79e6091d13 ... 537750\n20260318000000 add elements ref frame id 2026-05-06 17:27:34 True 33282b2c342e4743f096d1e3093146e243d97f392fe4df2cb5 ... 525250\n20260319000000 add sync id indexes 2026-05-06 17:27:34 True 22c7a18c918cfcc458f05fdbfe2a0b2bb65a67ae9daeec6028 ... 407083\n20260320000000 add note to meetings 2026-05-06 17:27:34 True cfa45b4c98e300c40cd36942839aa20528f47ae3e7b9c86751 ... 519625\n20260324000000 drop ocr text delete trigger 2026-05-06 17:27:34 True 99f445308168fc88f993c43f8e884cc4dc7e41411c86b4d3e7 ... 182209\n20260326000000 add session path to pipe executions 2026-05-06 17:27:34 True 5aa266dfcd7b741a18dd3ffb6b0ca3caf2e569959074cbc3ff ... 549583\n20260411000000 add elements ref frame id index 2026-05-06 17:27:34 True 378589322920e74980ea48c6b44c916cd488e47a8f6172161e ... 232083\n20260415000000 frames fts external content 2026-05-06 17:27:34 True 3fdac70da2fd44bca3c3717768b57c4cbee743451b73f13de9 ... 1259250\n20260423000000 add speaker id indexes 2026-05-06 17:27:34 True 80e8e0cf144ee620c81b3796196ca22b8e34f9c152ca2ffe8f ... 398709\n20260429000000 add evicted at to chunks 2026-05-06 17:27:34 True 180b1d44305df17620929a69ecce60fa3ce0148905adf19ff7 ... 963833\n20260502000000 add elements on screen 2026-05-06 17:27:34 True 2cf51a077a75ef32e4e1d722092053ce919bdeee151d3d91fb ... 644500\n20260504120000 add document path column 2026-05-06 17:27:34 True d84f7127e1647984eeb1f89e8dffd0918525f128e4608d323f ... 593042\n20260506120000 add memories sync columns 2026-05-07 06:45:22 True 800beaaa228c7fbd88fe367dc5b357adb72a3a0635da5a30f4 ... 1777417\n20260501000000 add redacted columns 2026-05-08 06:25:45 True 2a4cd6714a2322ccf8f2af6084af5a05e40f460c44c1aaf874 ... 795120667\n20260503000000 add frames image redacted 2026-05-08 06:25:45 True . It worked up to the point where I attemtped to remove it and install again since the retention policy doesn't clear old data and it was to big. I am basically moving data to nas and query it form there. mac is for capture only or lets say one week query using claude code. THe main consumer and interface is on nas. How to make it work so new changes won't messup my setup. Seems like I removed the whole folder it was working find runnign with @letest even I may be wrong.","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Show more","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:58","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Edit","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Claude responded: Looking at this carefully, the error tells the whole story:","depth":21,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Claude responded: Looking at this carefully, the error tells the whole story:","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Pinpointing schema mismatches from recent PII redaction migrations","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Pinpointing schema mismatches from recent PII redaction migrations","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Looking at this carefully, the error tells the whole story:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy to clipboard","depth":27,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"table nas.frames has 24 columns but 30 values were supplied","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Your source DB got 6 new columns from recent migrations, but the NAS archive was created earlier with the old schema.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CREATE TABLE IF NOT EXISTS","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"is a no-op when the table exists, so the NAS schema is frozen at whatever it was when first created. Then","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"INSERT ... SELECT *","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"does positional mapping, which blows up the moment column counts diverge.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Let me verify the recent screenpipe changes and then fix this properly.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Diagnosed schema drift, architected resilient migration strategy","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Diagnosed schema drift, architected resilient migration strategy","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"What's happening","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"What's happening","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"The error is schema drift, not a screenpipe bug. Your source DB grew 6 columns from these migrations (most landed late April / early May with the PII work):","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"20260429000000 add evicted at to chunks","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"→","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"video_chunks.evicted_at","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"20260502000000 add elements on screen","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"→","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"elements.on_screen","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"20260504120000 add document path column","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"→","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"frames.document_path","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"20260501000000 add redacted columns","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"→ redacted columns on frames/ocr_text/elements (this is the big one — accompanies the new","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"screenpipe/pii-redactor","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"model)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"20260503000000 add frames image redacted","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"→","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"frames.image_redacted_path","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"20260506120000 add memories sync columns","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"→ memories table","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Your NAS","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"archive.db","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"was created before these landed.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CREATE TABLE IF NOT EXISTS","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"is a no-op on existing tables, so the NAS schema froze. Then","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"INSERT INTO nas.frames SELECT * FROM main.frames","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"does","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"positional","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"mapping → 30 source values into a 24-column NAS table → parse error.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"You weren't wrong about","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"npx screenpipe@latest","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"working: removing the folder gave you a fresh local DB with the new schema, and querying still works because everything is on one schema. The mismatch only surfaces when you try to merge old + new schemas via the sync.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"The fix","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"The fix","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Two changes make this future-proof:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ensure_columns","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— before each insert, diff source vs NAS columns and run","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ALTER TABLE ADD COLUMN","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"for any new ones. SQLite handles this as a metadata-only op, so it's instant even on your 10G archive.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explicit column lists in INSERT","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— never","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SELECT *","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"again. Build the column list dynamically from","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PRAGMA table_info(<table>)","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"and use","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"INSERT INTO t (cols) SELECT cols FROM ...","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":". Now positional drift is structurally impossible.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bonus: dropped columns in future migrations will also be handled gracefully — the archive keeps the column with NULLs for new rows, no errors.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Let me write the updated script.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Created a file, ran a command, read a file","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Created a file, ran a command, read a file","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"What changed in the script","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"What changed in the script","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Three additions, everything else preserved:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Schema helpers","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"table_columns_with_types","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"table_columns","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"table_exists","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ensure_columns","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"build_col_list","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":") — pure bash + sqlite3 PRAGMA, no extra deps.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"New \"Reconciling NAS schema with source\" step","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— runs after","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CREATE TABLE IF NOT EXISTS","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", before indexes/FTS/inserts. For each table in","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SYNC_TABLES","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", it diffs source columns against NAS and","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ALTER TABLE ADD COLUMN","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"s the missing ones. Output looks like:","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy to clipboard","depth":27,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"schema: frames ✓ added 4: cloud_blob_id document_path image_redacted_path text_redacted","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"schema: elements ✓ added 2: on_screen text_redacted","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"schema: video_chunks ✓ added 1: evicted_at","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explicit column lists in every INSERT","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"—","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FRAMES_COLS=$(build_col_list frames)","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"builds","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"\"id\",\"timestamp\",\"app_name\",...","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"from source","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PRAGMA table_info","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", and the inserts use","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"INSERT INTO nas.t (cols) SELECT cols FROM main.t","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":". No more positional mapping. Column names are double-quoted so any future hyphens or reserved-word columns won't break parsing.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"What to expect on the next run","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"What to expect on the next run","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"First run after dropping it in: the \"Reconciling NAS schema with source\" step will print the missing columns it adds to your existing 10G archive (4 on","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"frames","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", plus a few on","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"elements","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"video_chunks","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ocr_text","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"). Each","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ALTER TABLE ADD COLUMN","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"is a metadata-only op in SQLite — no table rewrite, no VACUUM needed, total cost should be sub-second even on the 10G file. Then 2026-05-07 will sync normally.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"After that, when Screenpipe ships the next migration, your sync just picks up the new columns automatically. No more breakage.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"One thing worth knowing","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"One thing worth knowing","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"If Screenpipe ever","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"drops","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"a column in source (rare but possible — they did","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"drop ui monitoring","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"and","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"drop dead fts tables","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"earlier), the NAS will still have it, and","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"build_col_list","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(sourced from","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"main","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":") won't reference it. New rows will have NULL for the orphaned column, old rows keep their data. That's the right archival behavior — but if you ever want to actually drop those orphan columns from NAS, that's a manual","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ALTER TABLE ... DROP COLUMN","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"which SQLite has supported since 3.35 (your macOS Tahoe ships 3.43+, and your NAS Docker SQLite is fine).","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"View Screenpipe sync","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Screenpipe sync","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SH","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Open Screenpipe sync","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Open in iTerm","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Give positive feedback","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Give negative feedback","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"You said: ok but given the changes introduced is there something I may actually use","depth":20,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"You said: ok but given the changes introduced is there something I may actually use","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ok but given the changes introduced is there something I may actually use","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"12:06","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Edit","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Claude responded: Good question.","depth":21,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Claude responded: Good question.","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Cataloging PII redactor capabilities and security categories","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Cataloging PII redactor capabilities and security categories","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Good question. Let me look at what these new columns actually do and which ones map to your setup, since not all of them are equal value for you.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Evaluated four practical database columns for his specific workflow needs","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Evaluated four practical database columns for his specific workflow needs","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Yeah, three of them are genuinely useful for your setup. The rest are cloud-sync plumbing you can ignore.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"frames.document_path — most useful for you","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"frames.document_path","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— most useful for you","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Captures the path of the document/file open at frame time. This is a meaningful upgrade over relying on","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app_name","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"+","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"window_name","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"for IDE work.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Concrete uses given your stack:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Daily activity summary","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":": instead of \"spent 2h in PhpStorm\", you can group by","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"document_path","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"and get \"spent 2h in","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app/Http/Controllers/ReportsController.php","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"\" — directly tied to the JY-20458 work.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Ticket correlation","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":": branch names contain ticket IDs in PhpStorm window titles, but file paths are cleaner. Query","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"WHERE document_path LIKE '%/reports/%'","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"to slice by feature area.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Replaces some of the","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LIKE '%JY-%'","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"fishing","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":": your hyphenated-token issue with FTS5 mostly comes up in OCR text. For \"what was I working on\",","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"document_path","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"skips OCR entirely.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Worth adding an index on the NAS:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy to clipboard","depth":27,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"sql","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CREATE","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"INDEX","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IF","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"NOT","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"EXISTS","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"idx_frames_document_path","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ON","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"frames","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"document_path","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":")","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"WHERE","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"document_path","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IS","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"NOT","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"NULL","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":";","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"elements.on_screen — directly useful for the meeting detector","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"elements.on_screen","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— directly useful for the meeting detector","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"This is a boolean for whether the element was actually visible (vs. in the accessibility tree but scrolled off / occluded / behind a collapsed panel).","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"For your","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"meeting-detector","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"pipeline:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Zoom's accessibility tree exposes","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"everyone","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"on the call, including names in collapsed roster panels. Adding","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"WHERE on_screen = 1","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"cuts the participant detector down to people whose name tile was actually rendered — much closer to \"who was visible during this segment\".","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"For daily summaries: weights time-on-element by visibility, so reading vs. having-a-tab-open look different.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Cheap to add, big signal-to-noise win.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"PII redaction columns (text_redacted etc.) — useful but with caveats","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"PII redaction columns (","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"text_redacted","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"etc.) — useful but with caveats","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"The model behind these is","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"screenpipe/pii-redactor","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", fine-tuned for accessibility trees, OCR'd screen text, and computer-use traces. Detects 12 categories including a","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"secret","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"class that catches passwords, API keys, JWTs, DB connection strings, and PRIVATE-KEY markers — exactly the stuff that leaks into your captures during Laravel/Salesforce/HubSpot dev work.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"For your setup, this maps well because:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"The NAS archive is the consumer, queried by Claude Code agentically. Pointing those queries at","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"text_redacted","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"rather than","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"text","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"reduces the blast radius if a prompt or tool result ends up somewhere unexpected.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Your Mac captures Jiminny customer data on every call. Redacted text is safer for archival queries that don't need exact content (which is most of them).","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Caveats worth knowing before flipping it on:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Probably opt-in.","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Migrations only added the columns; redaction itself almost certainly needs a flag (worth checking","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"screenpipe record --help","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"for something like","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"--enable-pii-redaction","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"). Without enabling, the columns just stay NULL.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Over-redacts on short strings","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":": ~8% on accessibility/window titles, ~16% on long-form. Bulgarian names + Slovak surnames in your genealogy notes will likely trigger false positives. Keep the unredacted","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"text","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"column for cases where you need ground truth.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Model license is CC BY-NC 4.0","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— non-commercial only, so not suitable for anything Jiminny-business related; fine for personal use.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Practical pattern: query","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"text_redacted","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"by default, fall back to","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"text","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"only when you explicitly need the raw value.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"video_chunks.evicted_at — minor diagnostic value","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"video_chunks.evicted_at","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— minor diagnostic value","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"When the local retention policy prunes a chunk, this stamps the time. Given your 7-day retention + nightly sync to NAS, you could add a preflight check that warns if a chunk got evicted before its frames were synced (would mean you have frame metadata pointing to deleted video). Realistically your nightly sync at 3am is well inside the 7-day window, so this is more \"nice diagnostic\" than \"must-use\".","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Skip these","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Skip these","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"frames.cloud_blob_id","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"memories sync columns","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— for the optional E2EE cloud sync feature. You self-host, you don't need them. Stays NULL.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"If you want, I can draft a small SQL migration for the NAS-side indexes (","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"document_path","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"on_screen","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":") and a tweaked version of your daily-activity-summary Claude Code prompt that uses","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"document_path","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"for grouping. Both are short.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Give positive feedback","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Give negative feedback","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"You said: yes do it.","depth":20,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"You said: yes do it.","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"yes do it. I want frames.document_path and elements.on_screen. Do I need to add it to the script as well (if running for the first time on new machine). But for archive.db on nas I need to add it now. Also what would be the effect on older data if don't have data there?","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"12:16","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Edit","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Claude responded: Three deliverables coming up: the immediate NAS migration, the script patch, and an updated daily-summary prompt.","depth":21,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Claude responded: Three deliverables coming up: the immediate NAS migration, the script patch, and an updated daily-summary prompt.","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Architected migration strategy, index optimization, and data continuity implications","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Architected migration strategy, index optimization, and data continuity implications","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Three deliverables coming up: the immediate NAS migration, the script patch, and an updated daily-summary prompt. Plus a clean answer on the older-data question.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"What happens to older data","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"What happens to older data","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Both columns will be","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"NULL","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"for every row that's already in the archive. Screenpipe only started populating them on the migration dates (","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"document_path","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"from May 4,","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"on_screen","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"from May 2 in source — for your archive, from whenever you first sync data captured after those dates).","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Practical implications:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"WHERE document_path = 'foo'","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— silently skips all old rows. Same for","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"WHERE document_path IS NOT NULL","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"WHERE on_screen = 1","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— silently skips all old element rows (NULL is neither 1 nor 0).","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"WHERE on_screen = 0","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— also skips them (NULL ≠ 0).","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"So queries using these columns are implicitly forward-looking.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"No backfill is possible","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— screenpipe didn't capture this signal at the time, the data simply doesn't exist for those moments. If you need a hybrid query (use","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"document_path","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"when present, fall back to","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"window_name","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"for older data), use","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"COALESCE(document_path, window_name)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"or an explicit branching CASE.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"The partial indexes (with","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"WHERE ... IS NOT NULL","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":") handle this elegantly — they ignore old rows entirely, so they stay small and only grow with new data.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Run this now against the NAS archive","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Run this now against the NAS archive","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Two partial indexes — they index only the rows that actually have data, so they're effectively instant on your 10G archive (currently zero qualifying rows):","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy to clipboard","depth":27,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"bash","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"sqlite3 /Volumes/screenpipe/archive.db","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"<<","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"'SQL'","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CREATE INDEX IF NOT EXISTS idx_frames_document_path","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ON frames(document_path) WHERE document_path IS NOT NULL;","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CREATE INDEX IF NOT EXISTS idx_elements_onscreen_frame","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ON elements(frame_id) WHERE on_screen = 1 AND text IS NOT NULL;","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SQL","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Note on the second index: a plain index on","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"on_screen","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"alone is useless (boolean = 2 distinct values, low selectivity). The composite-partial form is what you actually want — it pre-filters to visible elements with text, anchored on","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"frame_id","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"for join performance, and complements rather than replaces your existing","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"idx_elements_frame_src_role","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Yes, add to the script for fresh installs","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Yes, add to the script for fresh installs","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"In the \"creating indexes\" heredoc in","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"screenpipe_sync.sh","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", add these two lines alongside the existing ones:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Edited a file, ran a command","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Edited a file, ran a command","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"On a fresh machine, the flow is:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CREATE TABLE IF NOT EXISTS ... AS SELECT * FROM main.frames WHERE 0","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"clones the source schema (so the columns appear automatically), and then","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CREATE INDEX IF NOT EXISTS","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"builds the partial indexes — both effectively no-ops since fresh data populates as it syncs. So yes, the patched script handles fresh installs correctly without further intervention.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Updated daily activity summary prompt","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Updated daily activity summary prompt","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"This uses both new columns, falls back gracefully for old data, and keeps the Europe/Sofia timezone conversion you already have.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Created a file, read a file","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Created a file, read a file","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Summary of what to do, in order","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Summary of what to do, in order","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Now","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":": run the two","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CREATE INDEX","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"statements above against","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Volumes/screenpipe/archive.db","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(sub-second since both are partial indexes on currently-empty conditions).","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Replace your existing script","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"with the patched","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"screenpipe_sync.sh","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— it has both the schema-drift handling from before and the two new indexes baked in.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Run a test sync","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"for 2026-05-07 — should now succeed, with the","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Reconciling NAS schema with source","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"step adding the missing columns to your existing 10G archive in one shot.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"From May 7 forward","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", queries against the NAS will see populated","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"document_path","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"and","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"on_screen","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"data. The new daily prompt will start producing useful file-level breakdowns; for backfilled days where those columns are NULL, it falls back to","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"window_name","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"grouping and notes the limitation.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"One side-thought for your meeting detector: when you next iterate on","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"pipeline.py","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", swap the participant scan to","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"WHERE on_screen = 1 OR on_screen IS NULL","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— old data still works, new data gets noise filtering for free. Same one-line change.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"View Daily activity prompt","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Daily activity prompt","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Document","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"·","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MD","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Open Daily activity prompt","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Open in Windsurf","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"View Screenpipe sync","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Screenpipe sync","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SH","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Open Screenpipe sync","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Open in iTerm","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Download all","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Download all","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Give positive feedback","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Give negative feedback","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"You said: I added lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.","depth":20,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"You said: I added lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"I added lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ll\ntotal 4612768\ndrwxr-xr-x 16 lukas staff 512 10 May 13:06 .\ndrwx------+ 94 lukas staff 3008 8 May 22:00 ..\n-rw-r--r--@ 1 lukas staff 6148 10 May 11:39 .DS_Store\ndrwxr-xr-x 19 lukas staff 608 10 May 11:39 data\n-rw-r--r--@ 1 lukas staff 2360483840 10 May 11:50 db.sqlite\n-rw-r--r--@ 1 lukas staff 32768 10 May 11:50 db.sqlite-shm\n-rw-r--r--@ 1 lukas staff 0 10 May 11:50 db.sqlite-wal\ndrwxr-xr-x 9 lukas staff 288 10 May 11:39 pipes\n-rw-r--r-- 1 lukas staff 28408 6 May 21:02 screenpipe.2026-05-06.0.log\n-rw-r--r-- 1 lukas staff 566164 7 May 21:50 screenpipe.2026-05-07.0.log\n-rw-r--r-- 1 lukas staff 382102 8 May 22:20 screenpipe.2026-05-08.0.log\n-rw-r--r-- 1 lukas staff 167023 9 May 23:04 screenpipe.2026-05-09.0.log\n-rw-r--r-- 1 lukas staff 7751 10 May 11:37 screenpipe.2026-05-10.0.log\n-rwxr-xr-x@ 1 lukas staff 14994 6 May 20:26 screenpipe_sync.sh\n-rw-r--r-- 1 lukas staff 19713 10 May 13:06 screenpipe_sync_updated.sh\n-rw-r--r--@ 1 lukas staff 4648 10 May 11:50 sync.log screepipe_sync_updated.sh. How to add it the rights to execute? Where is Daily activity prompt used? Also maybe lets include copying of logs to nas (like screenpipe.2026-05-10.0.log)","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Show more","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"13:08","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Edit","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Claude responded: Three quick fixes.","depth":21,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Claude responded: Three quick fixes.","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Orchestrated solutions for permissions, prompt usage, and log synchronization","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Orchestrated solutions for permissions, prompt usage, and log synchronization","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Three quick fixes. Let me handle them in order.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"1. Execute permissions + replace the old script","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"1. Execute permissions + replace the old script","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Your existing script at","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"screenpipe_sync.sh","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"is what cron calls (if you have cron set up). Cleanest path is to back up the old one, then move the updated version into its place — keeps cron working without touching crontab:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy to clipboard","depth":27,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"bash","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"cd","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"~/.screenpipe","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"chmod","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"+x screenpipe_sync_updated.sh","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"mv","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"screenpipe_sync.sh screenpipe_sync.sh.bak","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"mv","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"screenpipe_sync_updated.sh screenpipe_sync.sh","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"If you'd rather keep both around (e.g., to A/B test for a day), just do","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"chmod +x screenpipe_sync_updated.sh","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"and run it directly until you're happy, then swap.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"2. Where the daily activity prompt lives","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"2. Where the daily activity prompt lives","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"It's a Claude Code prompt template — input you feed to","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"claude","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"to generate the daily summary. A few placement options, in increasing order of integration:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Option A — manual invocation (simplest):","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Save to","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"~/.screenpipe/daily_activity_prompt.md","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", then:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy to clipboard","depth":27,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"bash","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TARGET_DATE","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"=","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"2026","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"-05-09","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DB_PATH","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"=","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Volumes/screenpipe/archive.db","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"sed","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"-e","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"\"s|\\","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"$TARGET_DATE","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"|","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"$TARGET_DATE","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"|g\"","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"-e","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"\"s|\\","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"$DB_PATH","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"|","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"$DB_PATH","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"|g\"","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"\\","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"~/.screenpipe/daily_activity_prompt.md","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"|","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"claude","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Option B — Claude Code custom slash command (most ergonomic):","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Claude Code reads","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"~/.claude/commands/*.md","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"as custom slash commands. Save the prompt there and invoke it as","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/daily","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"from a Claude Code session:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy to clipboard","depth":27,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"bash","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"mkdir","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"-p ~/.claude/commands","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"cp","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"~/.screenpipe/daily_activity_prompt.md ~/.claude/commands/daily.md","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Then in Claude Code:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/daily 2026-05-09","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"and Claude will run the SQL queries via its bash tool against the DB and produce the markdown.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Option C — wrapper script:","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"A small","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"~/.screenpipe/daily.sh","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"that takes a date arg and pipes the substituted prompt to","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"claude","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":". I can write this if you want — let me know which path you prefer (most likely B given how you work).","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"3. Adding log copying to the sync","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"3. Adding log copying to the sync","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Patching the script now. New section copies","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"screenpipe.YYYY-MM-DD.*.log","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"to","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"$NAS_MOUNT/logs/","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":". Flat directory rather than nested under each day, so you can","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"grep","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"across days easily.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Edited a file, ran a command, read a file","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Edited a file, ran a command, read a file","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Notes on the log copy behavior","depth":24,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Notes on the log copy behavior","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Glob handles rotation","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":":","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"screenpipe.$TARGET_DATE.*.log","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"catches any future","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".1.log","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".2.log","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"files if Screenpipe ever rotates within a day.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"nullglob","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ensures we don't get a literal pattern when there's no match.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"No","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"--ignore-existing","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":": when you sync","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"today","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", the log is still being written. Default rsync (","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"-a","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":") uses size+mtime to detect changes, so the next sync run will refresh it with the latest content.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Flat","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"logs/","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"directory on NAS","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":": easier to","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"grep -h \"ERROR\" logs/*.log","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"across days than walking nested per-date folders. If you'd rather have it under the date dir alongside frames, the change is one path swap.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"After running the new sync once, you should see:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy to clipboard","depth":27,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-8075191067953223507
|
8360685563245413392
|
idle
|
accessibility
|
NULL
|
Skip to content
Skip to content
Click to collapse
Skip to content
Skip to content
Click to collapse
⌘B
Drag to resize
Collapse sidebar
Search
Chat
Cowork
Code
New chat ⌘N
New chat
⌘N
Projects
Artifacts
Customize
Pinned
Bulgarian citizenship application process for EU residents
More options for Bulgarian citizenship application process for EU residents
Dawarich location tracking project
More options for Dawarich location tracking project
Recents
View all
Monthly expense tracking
More options for Monthly expense tracking
Exporting transaction data from Notion to finance hub
More options for Exporting transaction data from Notion to finance hub
Screenpipe sync script failing after recent migrations
More options for Screenpipe sync script failing after recent migrations
💬 How much have I spent for groc…
More options for 💬 How much have I spent for groc…
April 2026 spending by category
More options for April 2026 spending by category
Code diff review
More options for Code diff review
HubSpot rate limit implementation strategy
More options for HubSpot rate limit implementation strategy
Screenpipe retention policy code location
More options for Screenpipe retention policy code location
Viewing retention policy in screenpipe
More options for Viewing retention policy in screenpipe
Clean shot x video recording termination issue
More options for Clean shot x video recording termination issue
HubSpot rate limit handling with executeRequest
More options for HubSpot rate limit handling with executeRequest
Untitled
More options
💬 Screen pipe. Is there ability…
More options for 💬 Screen pipe. Is there ability…
SMB mount access inconsistency between Finder and iTerm
More options for SMB mount access inconsistency between Finder and iTerm
💬 What is the best switch I can…
More options for 💬 What is the best switch I can…
Permission denied on screenpipe volume
More options for Permission denied on screenpipe volume
Screenpipe sync database attachment error
More options for Screenpipe sync database attachment error
Last swimming outing with Dani
More options for Last swimming outing with Dani
Definition of incarcerated
More options for Definition of incarcerated
Chromecast remote volume buttons not working
More options for Chromecast remote volume buttons not working
Relaunch to update v1.6608.0
Relaunch to update
v1.6608.0
Lukas Pro
Get apps and extensions
Screenpipe sync script failing after recent migrations, rename chat
Screenpipe sync script failing after recent migrations
More options for Screenpipe sync script failing after recent migrations
Close
Claude is responding
You said: after recent updated in screenpipe (find out what are these) I am unable to run script.
You said: after recent updated in screenpipe (find out what are these) I am unable to run script.
Pasted Text, pasted, 353 lines
#!/bin/bash # screenpipe_sync.sh # Syncs Screenpipe SQLite data to a NAS archive database (append-only, no deletions). # Also copies the day's video/frame data folder to the NAS. # # Usage: # ./screenpipe_sync.sh # syncs yesterday (default) # ./screenpipe_sync.sh 2026-04-15 # sync
PASTED
after recent updated in screenpipe (find out what are these) I am unable to run script. (pasted) "lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ~/.screenpipe/screenpipe_sync.sh 2026-05-07
[2026-05-10 11:50:45] ========================================
[2026-05-10 11:50:45] Screenpipe sync starting for: 2026-05-07
[2026-05-10 11:50:45] ========================================
[+00m00s] ▶ Preflight checks
Source DB: OK (2.2G)
NAS mount: OK /Volumes/screenpipe
Archive DB: exists ( 10G)
Data dir: OK (266 files, 292M)
[+00m05s] ▶ Counting source rows for 2026-05-07
frames: 6262
elements: 623002
ui_events: 7412
ocr_text: 1670
meetings: 2
[+00m05s] ▶ Initialising tables, indexes, FTS
creating tables ✓ 0m00s
creating indexes ✓ 0m01s
creating FTS tables ✓ 0m00s
[+00m06s] ▶ Syncing data for 2026-05-07
video_chunks ✓ 0m01s
frames (6262 rows) ⠋ Parse error near line 3: table nas.frames has 24 columns but 30 values were supplied" There were some recent changes in migrations. Here are migrations form the begining of march (approx after I installed irt first time) 20260301000000 create elements table 2026-05-06 17:27:34 True 736637f38c6e0b5547f23c870ebbc3e87ef2d8d33b22ce73f7 ... 1302167
20260301100000 fts external content 2026-05-06 17:27:34 True 44ca0e5fc3b23c19aa09d7ac3fea48de604032d5feced2615c ... 2102875
20260301200000 drop ui monitoring 2026-05-06 17:27:34 True 9ab8a4d8c0d602b491ef1a6ff36076fd7b7c12c05848201682 ... 620375
20260306000000 delete empty transcriptions 2026-05-06 17:27:34 True 5f991a21d663157a2bce5cb9f0729f02181eef817aaef5a0b8 ... 166792
20260309000000 add cloud blob id 2026-05-06 17:27:34 True e1588e32884ec5660d11bbaa995d767fb2172bb9732ad22319 ... 1450542
20260310000000 create memories 2026-05-06 17:27:34 True 4fd07e878de1dd5b8d184e7bca9ee4e6b2480bbf39e5a68ff7 ... 1135416
20260311000000 drop unused tables 2026-05-06 17:27:34 True 3d9eb9d327a61c4055b31e22082cd045e00bd7a875cbdee86b ... 547625
20260312000000 consolidate search to frames full text 2026-05-06 17:27:34 True 5a7a31a359e9e93978d46ab4759fc8cd43898c0fd325d001b7 ... 3038250
20260312000001 drop dead fts tables 2026-05-06 17:27:34 True dd8264b96b4427f40b06ac60b813b77b6d055b24dd727212c5 ... 297250
20260312000002 drop accessibility tags 2026-05-06 17:27:34 True 672b2661f7e0fc8026f2eb6cc5d24935a15db4ed4982aeb973 ... 260167
20260315000000 add frame id to memories 2026-05-06 17:27:34 True f324ec7981134e647b6497126a2b6a7467e94d271d140d0d25 ... 642250
20260316000000 add elements activity summary index 2026-05-06 17:27:34 True 5b3f99a0d58fc73d62f240319d0718963364fdee1e3a7c4866 ... 265834
20260317000000 add elements automation props 2026-05-06 17:27:34 True 4bd132d263de143c7bb0dcf2e3b8074606c58c0f79e6091d13 ... 537750
20260318000000 add elements ref frame id 2026-05-06 17:27:34 True 33282b2c342e4743f096d1e3093146e243d97f392fe4df2cb5 ... 525250
20260319000000 add sync id indexes 2026-05-06 17:27:34 True 22c7a18c918cfcc458f05fdbfe2a0b2bb65a67ae9daeec6028 ... 407083
20260320000000 add note to meetings 2026-05-06 17:27:34 True cfa45b4c98e300c40cd36942839aa20528f47ae3e7b9c86751 ... 519625
20260324000000 drop ocr text delete trigger 2026-05-06 17:27:34 True 99f445308168fc88f993c43f8e884cc4dc7e41411c86b4d3e7 ... 182209
20260326000000 add session path to pipe executions 2026-05-06 17:27:34 True 5aa266dfcd7b741a18dd3ffb6b0ca3caf2e569959074cbc3ff ... 549583
20260411000000 add elements ref frame id index 2026-05-06 17:27:34 True 378589322920e74980ea48c6b44c916cd488e47a8f6172161e ... 232083
20260415000000 frames fts external content 2026-05-06 17:27:34 True 3fdac70da2fd44bca3c3717768b57c4cbee743451b73f13de9 ... 1259250
20260423000000 add speaker id indexes 2026-05-06 17:27:34 True 80e8e0cf144ee620c81b3796196ca22b8e34f9c152ca2ffe8f ... 398709
20260429000000 add evicted at to chunks 2026-05-06 17:27:34 True 180b1d44305df17620929a69ecce60fa3ce0148905adf19ff7 ... 963833
20260502000000 add elements on screen 2026-05-06 17:27:34 True 2cf51a077a75ef32e4e1d722092053ce919bdeee151d3d91fb ... 644500
20260504120000 add document path column 2026-05-06 17:27:34 True d84f7127e1647984eeb1f89e8dffd0918525f128e4608d323f ... 593042
20260506120000 add memories sync columns 2026-05-07 06:45:22 True 800beaaa228c7fbd88fe367dc5b357adb72a3a0635da5a30f4 ... 1777417
20260501000000 add redacted columns 2026-05-08 06:25:45 True 2a4cd6714a2322ccf8f2af6084af5a05e40f460c44c1aaf874 ... 795120667
20260503000000 add frames image redacted 2026-05-08 06:25:45 True . It worked up to the point where I attemtped to remove it and install again since the retention policy doesn't clear old data and it was to big. I am basically moving data to nas and query it form there. mac is for capture only or lets say one week query using claude code. THe main consumer and interface is on nas. How to make it work so new changes won't messup my setup. Seems like I removed the whole folder it was working find runnign with @letest even I may be wrong.
Show more
11:58
Edit
Copy
Claude responded: Looking at this carefully, the error tells the whole story:
Claude responded: Looking at this carefully, the error tells the whole story:
Pinpointing schema mismatches from recent PII redaction migrations
Pinpointing schema mismatches from recent PII redaction migrations
Looking at this carefully, the error tells the whole story:
Copy to clipboard
table nas.frames has 24 columns but 30 values were supplied
Your source DB got 6 new columns from recent migrations, but the NAS archive was created earlier with the old schema.
CREATE TABLE IF NOT EXISTS
is a no-op when the table exists, so the NAS schema is frozen at whatever it was when first created. Then
INSERT ... SELECT *
does positional mapping, which blows up the moment column counts diverge.
Let me verify the recent screenpipe changes and then fix this properly.
Diagnosed schema drift, architected resilient migration strategy
Diagnosed schema drift, architected resilient migration strategy
What's happening
What's happening
The error is schema drift, not a screenpipe bug. Your source DB grew 6 columns from these migrations (most landed late April / early May with the PII work):
20260429000000 add evicted at to chunks
→
video_chunks.evicted_at
20260502000000 add elements on screen
→
elements.on_screen
20260504120000 add document path column
→
frames.document_path
20260501000000 add redacted columns
→ redacted columns on frames/ocr_text/elements (this is the big one — accompanies the new
screenpipe/pii-redactor
model)
20260503000000 add frames image redacted
→
frames.image_redacted_path
20260506120000 add memories sync columns
→ memories table
Your NAS
archive.db
was created before these landed.
CREATE TABLE IF NOT EXISTS
is a no-op on existing tables, so the NAS schema froze. Then
INSERT INTO nas.frames SELECT * FROM main.frames
does
positional
mapping → 30 source values into a 24-column NAS table → parse error.
You weren't wrong about
npx screenpipe@latest
working: removing the folder gave you a fresh local DB with the new schema, and querying still works because everything is on one schema. The mismatch only surfaces when you try to merge old + new schemas via the sync.
The fix
The fix
Two changes make this future-proof:
ensure_columns
— before each insert, diff source vs NAS columns and run
ALTER TABLE ADD COLUMN
for any new ones. SQLite handles this as a metadata-only op, so it's instant even on your 10G archive.
Explicit column lists in INSERT
— never
SELECT *
again. Build the column list dynamically from
PRAGMA table_info(<table>)
and use
INSERT INTO t (cols) SELECT cols FROM ...
. Now positional drift is structurally impossible.
Bonus: dropped columns in future migrations will also be handled gracefully — the archive keeps the column with NULLs for new rows, no errors.
Let me write the updated script.
Created a file, ran a command, read a file
Created a file, ran a command, read a file
What changed in the script
What changed in the script
Three additions, everything else preserved:
Schema helpers
(
table_columns_with_types
,
table_columns
,
table_exists
,
ensure_columns
,
build_col_list
) — pure bash + sqlite3 PRAGMA, no extra deps.
New "Reconciling NAS schema with source" step
— runs after
CREATE TABLE IF NOT EXISTS
, before indexes/FTS/inserts. For each table in
SYNC_TABLES
, it diffs source columns against NAS and
ALTER TABLE ADD COLUMN
s the missing ones. Output looks like:
Copy to clipboard
schema: frames ✓ added 4: cloud_blob_id document_path image_redacted_path text_redacted
schema: elements ✓ added 2: on_screen text_redacted
schema: video_chunks ✓ added 1: evicted_at
Explicit column lists in every INSERT
—
FRAMES_COLS=$(build_col_list frames)
builds
"id","timestamp","app_name",...
from source
PRAGMA table_info
, and the inserts use
INSERT INTO nas.t (cols) SELECT cols FROM main.t
. No more positional mapping. Column names are double-quoted so any future hyphens or reserved-word columns won't break parsing.
What to expect on the next run
What to expect on the next run
First run after dropping it in: the "Reconciling NAS schema with source" step will print the missing columns it adds to your existing 10G archive (4 on
frames
, plus a few on
elements
/
video_chunks
/
ocr_text
). Each
ALTER TABLE ADD COLUMN
is a metadata-only op in SQLite — no table rewrite, no VACUUM needed, total cost should be sub-second even on the 10G file. Then 2026-05-07 will sync normally.
After that, when Screenpipe ships the next migration, your sync just picks up the new columns automatically. No more breakage.
One thing worth knowing
One thing worth knowing
If Screenpipe ever
drops
a column in source (rare but possible — they did
drop ui monitoring
and
drop dead fts tables
earlier), the NAS will still have it, and
build_col_list
(sourced from
main
) won't reference it. New rows will have NULL for the orphaned column, old rows keep their data. That's the right archival behavior — but if you ever want to actually drop those orphan columns from NAS, that's a manual
ALTER TABLE ... DROP COLUMN
which SQLite has supported since 3.35 (your macOS Tahoe ships 3.43+, and your NAS Docker SQLite is fine).
View Screenpipe sync
Screenpipe sync
SH
Open Screenpipe sync
Open in iTerm
Copy
Give positive feedback
Give negative feedback
You said: ok but given the changes introduced is there something I may actually use
You said: ok but given the changes introduced is there something I may actually use
ok but given the changes introduced is there something I may actually use
12:06
Edit
Copy
Claude responded: Good question.
Claude responded: Good question.
Cataloging PII redactor capabilities and security categories
Cataloging PII redactor capabilities and security categories
Good question. Let me look at what these new columns actually do and which ones map to your setup, since not all of them are equal value for you.
Evaluated four practical database columns for his specific workflow needs
Evaluated four practical database columns for his specific workflow needs
Yeah, three of them are genuinely useful for your setup. The rest are cloud-sync plumbing you can ignore.
frames.document_path — most useful for you
frames.document_path
— most useful for you
Captures the path of the document/file open at frame time. This is a meaningful upgrade over relying on
app_name
+
window_name
for IDE work.
Concrete uses given your stack:
Daily activity summary
: instead of "spent 2h in PhpStorm", you can group by
document_path
and get "spent 2h in
app/Http/Controllers/ReportsController.php
" — directly tied to the JY-20458 work.
Ticket correlation
: branch names contain ticket IDs in PhpStorm window titles, but file paths are cleaner. Query
WHERE document_path LIKE '%/reports/%'
to slice by feature area.
Replaces some of the
LIKE '%JY-%'
fishing
: your hyphenated-token issue with FTS5 mostly comes up in OCR text. For "what was I working on",
document_path
skips OCR entirely.
Worth adding an index on the NAS:
Copy to clipboard
sql
CREATE
INDEX
IF
NOT
EXISTS
idx_frames_document_path
ON
frames
(
document_path
)
WHERE
document_path
IS
NOT
NULL
;
elements.on_screen — directly useful for the meeting detector
elements.on_screen
— directly useful for the meeting detector
This is a boolean for whether the element was actually visible (vs. in the accessibility tree but scrolled off / occluded / behind a collapsed panel).
For your
meeting-detector
pipeline:
Zoom's accessibility tree exposes
everyone
on the call, including names in collapsed roster panels. Adding
WHERE on_screen = 1
cuts the participant detector down to people whose name tile was actually rendered — much closer to "who was visible during this segment".
For daily summaries: weights time-on-element by visibility, so reading vs. having-a-tab-open look different.
Cheap to add, big signal-to-noise win.
PII redaction columns (text_redacted etc.) — useful but with caveats
PII redaction columns (
text_redacted
etc.) — useful but with caveats
The model behind these is
screenpipe/pii-redactor
, fine-tuned for accessibility trees, OCR'd screen text, and computer-use traces. Detects 12 categories including a
secret
class that catches passwords, API keys, JWTs, DB connection strings, and PRIVATE-KEY markers — exactly the stuff that leaks into your captures during Laravel/Salesforce/HubSpot dev work.
For your setup, this maps well because:
The NAS archive is the consumer, queried by Claude Code agentically. Pointing those queries at
text_redacted
rather than
text
reduces the blast radius if a prompt or tool result ends up somewhere unexpected.
Your Mac captures Jiminny customer data on every call. Redacted text is safer for archival queries that don't need exact content (which is most of them).
Caveats worth knowing before flipping it on:
Probably opt-in.
Migrations only added the columns; redaction itself almost certainly needs a flag (worth checking
screenpipe record --help
for something like
--enable-pii-redaction
). Without enabling, the columns just stay NULL.
Over-redacts on short strings
: ~8% on accessibility/window titles, ~16% on long-form. Bulgarian names + Slovak surnames in your genealogy notes will likely trigger false positives. Keep the unredacted
text
column for cases where you need ground truth.
Model license is CC BY-NC 4.0
— non-commercial only, so not suitable for anything Jiminny-business related; fine for personal use.
Practical pattern: query
text_redacted
by default, fall back to
text
only when you explicitly need the raw value.
video_chunks.evicted_at — minor diagnostic value
video_chunks.evicted_at
— minor diagnostic value
When the local retention policy prunes a chunk, this stamps the time. Given your 7-day retention + nightly sync to NAS, you could add a preflight check that warns if a chunk got evicted before its frames were synced (would mean you have frame metadata pointing to deleted video). Realistically your nightly sync at 3am is well inside the 7-day window, so this is more "nice diagnostic" than "must-use".
Skip these
Skip these
frames.cloud_blob_id
,
memories sync columns
— for the optional E2EE cloud sync feature. You self-host, you don't need them. Stays NULL.
If you want, I can draft a small SQL migration for the NAS-side indexes (
document_path
,
on_screen
) and a tweaked version of your daily-activity-summary Claude Code prompt that uses
document_path
for grouping. Both are short.
Copy
Give positive feedback
Give negative feedback
You said: yes do it.
You said: yes do it.
yes do it. I want frames.document_path and elements.on_screen. Do I need to add it to the script as well (if running for the first time on new machine). But for archive.db on nas I need to add it now. Also what would be the effect on older data if don't have data there?
12:16
Edit
Copy
Claude responded: Three deliverables coming up: the immediate NAS migration, the script patch, and an updated daily-summary prompt.
Claude responded: Three deliverables coming up: the immediate NAS migration, the script patch, and an updated daily-summary prompt.
Architected migration strategy, index optimization, and data continuity implications
Architected migration strategy, index optimization, and data continuity implications
Three deliverables coming up: the immediate NAS migration, the script patch, and an updated daily-summary prompt. Plus a clean answer on the older-data question.
What happens to older data
What happens to older data
Both columns will be
NULL
for every row that's already in the archive. Screenpipe only started populating them on the migration dates (
document_path
from May 4,
on_screen
from May 2 in source — for your archive, from whenever you first sync data captured after those dates).
Practical implications:
WHERE document_path = 'foo'
— silently skips all old rows. Same for
WHERE document_path IS NOT NULL
.
WHERE on_screen = 1
— silently skips all old element rows (NULL is neither 1 nor 0).
WHERE on_screen = 0
— also skips them (NULL ≠ 0).
So queries using these columns are implicitly forward-looking.
No backfill is possible
— screenpipe didn't capture this signal at the time, the data simply doesn't exist for those moments. If you need a hybrid query (use
document_path
when present, fall back to
window_name
for older data), use
COALESCE(document_path, window_name)
or an explicit branching CASE.
The partial indexes (with
WHERE ... IS NOT NULL
) handle this elegantly — they ignore old rows entirely, so they stay small and only grow with new data.
Run this now against the NAS archive
Run this now against the NAS archive
Two partial indexes — they index only the rows that actually have data, so they're effectively instant on your 10G archive (currently zero qualifying rows):
Copy to clipboard
bash
sqlite3 /Volumes/screenpipe/archive.db
<<
'SQL'
CREATE INDEX IF NOT EXISTS idx_frames_document_path
ON frames(document_path) WHERE document_path IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_elements_onscreen_frame
ON elements(frame_id) WHERE on_screen = 1 AND text IS NOT NULL;
SQL
Note on the second index: a plain index on
on_screen
alone is useless (boolean = 2 distinct values, low selectivity). The composite-partial form is what you actually want — it pre-filters to visible elements with text, anchored on
frame_id
for join performance, and complements rather than replaces your existing
idx_elements_frame_src_role
.
Yes, add to the script for fresh installs
Yes, add to the script for fresh installs
In the "creating indexes" heredoc in
screenpipe_sync.sh
, add these two lines alongside the existing ones:
Edited a file, ran a command
Edited a file, ran a command
On a fresh machine, the flow is:
CREATE TABLE IF NOT EXISTS ... AS SELECT * FROM main.frames WHERE 0
clones the source schema (so the columns appear automatically), and then
CREATE INDEX IF NOT EXISTS
builds the partial indexes — both effectively no-ops since fresh data populates as it syncs. So yes, the patched script handles fresh installs correctly without further intervention.
Updated daily activity summary prompt
Updated daily activity summary prompt
This uses both new columns, falls back gracefully for old data, and keeps the Europe/Sofia timezone conversion you already have.
Created a file, read a file
Created a file, read a file
Summary of what to do, in order
Summary of what to do, in order
Now
: run the two
CREATE INDEX
statements above against
/Volumes/screenpipe/archive.db
(sub-second since both are partial indexes on currently-empty conditions).
Replace your existing script
with the patched
screenpipe_sync.sh
— it has both the schema-drift handling from before and the two new indexes baked in.
Run a test sync
for 2026-05-07 — should now succeed, with the
Reconciling NAS schema with source
step adding the missing columns to your existing 10G archive in one shot.
From May 7 forward
, queries against the NAS will see populated
document_path
and
on_screen
data. The new daily prompt will start producing useful file-level breakdowns; for backfilled days where those columns are NULL, it falls back to
window_name
grouping and notes the limitation.
One side-thought for your meeting detector: when you next iterate on
pipeline.py
, swap the participant scan to
WHERE on_screen = 1 OR on_screen IS NULL
— old data still works, new data gets noise filtering for free. Same one-line change.
View Daily activity prompt
Daily activity prompt
Document
·
MD
Open Daily activity prompt
Open in Windsurf
View Screenpipe sync
Screenpipe sync
SH
Open Screenpipe sync
Open in iTerm
Download all
Download all
Copy
Give positive feedback
Give negative feedback
You said: I added lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.
You said: I added lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.
I added lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ll
total 4612768
drwxr-xr-x 16 lukas staff 512 10 May 13:06 .
drwx------+ 94 lukas staff 3008 8 May 22:00 ..
-rw-r--r--@ 1 lukas staff 6148 10 May 11:39 .DS_Store
drwxr-xr-x 19 lukas staff 608 10 May 11:39 data
-rw-r--r--@ 1 lukas staff 2360483840 10 May 11:50 db.sqlite
-rw-r--r--@ 1 lukas staff 32768 10 May 11:50 db.sqlite-shm
-rw-r--r--@ 1 lukas staff 0 10 May 11:50 db.sqlite-wal
drwxr-xr-x 9 lukas staff 288 10 May 11:39 pipes
-rw-r--r-- 1 lukas staff 28408 6 May 21:02 screenpipe.2026-05-06.0.log
-rw-r--r-- 1 lukas staff 566164 7 May 21:50 screenpipe.2026-05-07.0.log
-rw-r--r-- 1 lukas staff 382102 8 May 22:20 screenpipe.2026-05-08.0.log
-rw-r--r-- 1 lukas staff 167023 9 May 23:04 screenpipe.2026-05-09.0.log
-rw-r--r-- 1 lukas staff 7751 10 May 11:37 screenpipe.2026-05-10.0.log
-rwxr-xr-x@ 1 lukas staff 14994 6 May 20:26 screenpipe_sync.sh
-rw-r--r-- 1 lukas staff 19713 10 May 13:06 screenpipe_sync_updated.sh
-rw-r--r--@ 1 lukas staff 4648 10 May 11:50 sync.log screepipe_sync_updated.sh. How to add it the rights to execute? Where is Daily activity prompt used? Also maybe lets include copying of logs to nas (like screenpipe.2026-05-10.0.log)
Show more
13:08
Edit
Copy
Claude responded: Three quick fixes.
Claude responded: Three quick fixes.
Orchestrated solutions for permissions, prompt usage, and log synchronization
Orchestrated solutions for permissions, prompt usage, and log synchronization
Three quick fixes. Let me handle them in order.
1. Execute permissions + replace the old script
1. Execute permissions + replace the old script
Your existing script at
screenpipe_sync.sh
is what cron calls (if you have cron set up). Cleanest path is to back up the old one, then move the updated version into its place — keeps cron working without touching crontab:
Copy to clipboard
bash
cd
~/.screenpipe
chmod
+x screenpipe_sync_updated.sh
mv
screenpipe_sync.sh screenpipe_sync.sh.bak
mv
screenpipe_sync_updated.sh screenpipe_sync.sh
If you'd rather keep both around (e.g., to A/B test for a day), just do
chmod +x screenpipe_sync_updated.sh
and run it directly until you're happy, then swap.
2. Where the daily activity prompt lives
2. Where the daily activity prompt lives
It's a Claude Code prompt template — input you feed to
claude
to generate the daily summary. A few placement options, in increasing order of integration:
Option A — manual invocation (simplest):
Save to
~/.screenpipe/daily_activity_prompt.md
, then:
Copy to clipboard
bash
TARGET_DATE
=
2026
-05-09
DB_PATH
=
/Volumes/screenpipe/archive.db
sed
-e
"s|\
$TARGET_DATE
|
$TARGET_DATE
|g"
-e
"s|\
$DB_PATH
|
$DB_PATH
|g"
\
~/.screenpipe/daily_activity_prompt.md
|
claude
Option B — Claude Code custom slash command (most ergonomic):
Claude Code reads
~/.claude/commands/*.md
as custom slash commands. Save the prompt there and invoke it as
/daily
from a Claude Code session:
Copy to clipboard
bash
mkdir
-p ~/.claude/commands
cp
~/.screenpipe/daily_activity_prompt.md ~/.claude/commands/daily.md
Then in Claude Code:
/daily 2026-05-09
and Claude will run the SQL queries via its bash tool against the DB and produce the markdown.
Option C — wrapper script:
A small
~/.screenpipe/daily.sh
that takes a date arg and pipes the substituted prompt to
claude
. I can write this if you want — let me know which path you prefer (most likely B given how you work).
3. Adding log copying to the sync
3. Adding log copying to the sync
Patching the script now. New section copies
screenpipe.YYYY-MM-DD.*.log
to
$NAS_MOUNT/logs/
. Flat directory rather than nested under each day, so you can
grep
across days easily.
Edited a file, ran a command, read a file
Edited a file, ran a command, read a file
Notes on the log copy behavior
Notes on the log copy behavior
Glob handles rotation
:
screenpipe.$TARGET_DATE.*.log
catches any future
.1.log
,
.2.log
files if Screenpipe ever rotates within a day.
nullglob
ensures we don't get a literal pattern when there's no match.
No
--ignore-existing
: when you sync
today
, the log is still being written. Default rsync (
-a
) uses size+mtime to detect changes, so the next sync run will refresh it with the latest content.
Flat
logs/
directory on NAS
: easier to
grep -h "ERROR" logs/*.log
across days than walking nested per-date folders. If you'd rather have it under the date dir alongside frames, the change is one path swap.
After running the new sync once, you should see:
Copy to clipboard...
|
14728
|
NULL
|
NULL
|
NULL
|
|
15784
|
698
|
6
|
2026-05-11T07:14:39.502072+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778483679502_m1.jpg...
|
PhpStorm
|
faVsco.js – HubspotPaginationService.php
|
True
|
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
12
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot\Pagination;
use Jiminny\Services\Crm\Hubspot\Client;
use Jiminny\Services\Crm\Hubspot\PayloadBuilder;
use Psr\Log\LoggerInterface;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
class HubspotPaginationService
{
public function __construct(
private LoggerInterface $logger
) {
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
Client $client,
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
$state = new PaginationState(offset: $offset);
$endpoint = Client::BASE_URL . "/crm/v3/objects/{$type}/search";
$defaultFilter = $payload['filters'] ?? [];
$resultsPerPage = PayloadBuilder::MAX_SEARCH_REQUEST_LIMIT;
$teamId = $client->getConfig()->getTeam()->getId();
$delay = $this->calculateDelayInMicroseconds();
do {
if ($this->shouldStopPagination($state, $teamId)) {
break;
}
$payload = $this->handlePaginationStrategy($payload, $defaultFilter, $state, $resultsPerPage, $teamId);
$this->validateTokenIfNeeded($client, $state);
if ($state->requestCount > 0) {
usleep($delay);
}
$page = $this->executeSearchRequest($client, $type, $payload, $state);
$state->setTotal($page['total'] ?? 0);
$this->updateLastRecordId($page, $state);
// Safely iterate over results with null check
$results = $page['results'] ?? [];
foreach ($results as $row) {
$state->incrementTotalRecords();
yield $row;
}
$state->setOffset($this->getNextOffset($page));
$state->incrementRequestCount();
$this->logPaginationProgress($state, $teamId, $endpoint);
} while ($state->offset && ! empty($page['results']));
// Log final pagination completion stats
$this->logger->info('[Hubspot] Pagination completed', [
'team_id' => $teamId,
'endpoint' => $endpoint,
'total_requests' => $state->requestCount,
'total_records_fetched' => $state->totalRecords,
'total_elapsed_seconds' => round($state->getElapsedSeconds(), 2),
'average_seconds_per_request' => $state->requestCount > 0 ? round($state->getElapsedSeconds() / $state->requestCount, 2) : 0,
]);
// Update reference parameters
$total = $state->total;
$lastRecordId = $state->lastRecordId;
}
private function shouldStopPagination(PaginationState $state, int $teamId): bool
{
if ($state->hasReachedSafetyLimit()) {
$this->logger->warning('[Hubspot] Reached maximum request limit during pagination', [
'team_id' => $teamId,
'safety_limit' => PaginationConfig::LOOP_SAFETY_LIMIT,
'total_fetched' => $state->totalRecords,
]);
return true;
}
return false;
}
private function handlePaginationStrategy(
array $payload,
array $defaultFilter,
PaginationState $state,
int $resultsPerPage,
int $teamId
): array {
if ($this->shouldSwitchToKeysetPagination($state, $resultsPerPage)) {
$payload['filters'] = $defaultFilter;
$payload['filters'][] = [
'propertyName' => 'hs_object_id',
'operator' => 'LT',
'value' => $state->lastRecordId,
];
$this->logger->info('[Hubspot] Search keyset pagination request', [
'team_id' => $teamId,
'sequence' => $state->requestCount,
'itemsPerPage' => $resultsPerPage,
'payload' => $payload,
'total' => $state->total,
]);
unset($payload['after']);
$state->setOffset(0);
}
if ($state->offset) {
$payload['after'] = $state->offset;
}
return $payload;
}
private function shouldSwitchToKeysetPagination(PaginationState $state, int $resultsPerPage): bool
{
// Check if we've hit the offset limit
$shouldSwitch = $state->requestCount > 0 && ($state->offset + $resultsPerPage) > PaginationConfig::TOTAL_QUERY_LIMIT;
if ($shouldSwitch && $state->lastRecordId === null) {
$this->logger->warning('[Hubspot] Cannot switch to keyset pagination: lastRecordId is null', [
'request_count' => $state->requestCount,
'current_offset' => $state->offset,
'results_per_page' => $resultsPerPage,
'total_query_limit' => PaginationConfig::TOTAL_QUERY_LIMIT,
]);
return false; // Continue with offset pagination
}
return $shouldSwitch;
}
private function validateTokenIfNeeded(Client $client, PaginationState $state): void
{
if ($state->shouldValidateToken()) {
$client->ensureValidToken();
$state->updateLastTokenCheck();
}
}
private function executeSearchRequest(Client $client, string $objectType, array $payload, PaginationState $state): array
{
try {
return $client->search($objectType, $payload);
} catch (\Exception $e) {
if ($client->isUnauthorizedException($e)) {
$this->logger->warning('[Hubspot] Got 401 during pagination, attempting token refresh', [
'team_id' => $client->getConfig()->getTeam()->getId(),
'error' => $e->getMessage(),
]);
$client->ensureValidToken();
$state->updateLastTokenCheck();
try {
$result = $client->search($objectType, $payload);
$this->logger->info('[Hubspot] Token refresh and retry successful', [
'team_id' => $client->getConfig()->getTeam()->getId(),
]);
return $result;
} catch (\Exception $retryException) {
$this->logger->error('[Hubspot] Retry request failed after token refresh', [
'team_id' => $client->getConfig()->getTeam()->getId(),
'original_error' => $e->getMessage(),
'retry_error' => $retryException->getMessage(),
]);
throw $retryException;
}
}
// RateLimitException and other exceptions are re-thrown as-is
throw $e;
}
}
private function updateLastRecordId(array $page, PaginationState $state): void
{
$lastRecord = ! empty($page['results']) ? end($page['results']) : null;
$lastRecordId = $lastRecord['id'] ?? null;
$state->updateLastRecordId($lastRecordId);
}
private function getNextOffset(array $page): int
{
return isset($page['paging']['next']['after']) ? (int) $page['paging']['next']['after'] : 0;
}
private function logPaginationProgress(PaginationState $state, int $teamId, string $endpoint): void
{
if ($state->shouldLogProgress()) {
$this->logger->info('[Hubspot] Pagination progress log', [
'team_id' => $teamId,
'endpoint' => $endpoint,
'requests_made' => $state->requestCount,
'records_fetched' => $state->totalRecords,
'elapsed_seconds' => $state->getElapsedSeconds(),
]);
}
}
private function calculateDelayInMicroseconds(): int
{
return (int) (1 / PaginationConfig::SEARCH_RPS_LIMIT * 1000000);
}
}
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"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options...
|
[{"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":"12","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\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot\\Pagination;\n\nuse Jiminny\\Services\\Crm\\Hubspot\\Client;\nuse Jiminny\\Services\\Crm\\Hubspot\\PayloadBuilder;\nuse Psr\\Log\\LoggerInterface;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\n\nclass HubspotPaginationService\n{\n public function __construct(\n private LoggerInterface $logger\n ) {\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n Client $client,\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n $state = new PaginationState(offset: $offset);\n $endpoint = Client::BASE_URL . \"/crm/v3/objects/{$type}/search\";\n $defaultFilter = $payload['filters'] ?? [];\n $resultsPerPage = PayloadBuilder::MAX_SEARCH_REQUEST_LIMIT;\n $teamId = $client->getConfig()->getTeam()->getId();\n $delay = $this->calculateDelayInMicroseconds();\n\n do {\n if ($this->shouldStopPagination($state, $teamId)) {\n break;\n }\n\n $payload = $this->handlePaginationStrategy($payload, $defaultFilter, $state, $resultsPerPage, $teamId);\n\n $this->validateTokenIfNeeded($client, $state);\n if ($state->requestCount > 0) {\n usleep($delay);\n }\n\n $page = $this->executeSearchRequest($client, $type, $payload, $state);\n\n $state->setTotal($page['total'] ?? 0);\n $this->updateLastRecordId($page, $state);\n\n // Safely iterate over results with null check\n $results = $page['results'] ?? [];\n foreach ($results as $row) {\n $state->incrementTotalRecords();\n yield $row;\n }\n\n $state->setOffset($this->getNextOffset($page));\n $state->incrementRequestCount();\n\n $this->logPaginationProgress($state, $teamId, $endpoint);\n } while ($state->offset && ! empty($page['results']));\n\n // Log final pagination completion stats\n $this->logger->info('[Hubspot] Pagination completed', [\n 'team_id' => $teamId,\n 'endpoint' => $endpoint,\n 'total_requests' => $state->requestCount,\n 'total_records_fetched' => $state->totalRecords,\n 'total_elapsed_seconds' => round($state->getElapsedSeconds(), 2),\n 'average_seconds_per_request' => $state->requestCount > 0 ? round($state->getElapsedSeconds() / $state->requestCount, 2) : 0,\n ]);\n\n // Update reference parameters\n $total = $state->total;\n $lastRecordId = $state->lastRecordId;\n }\n\n private function shouldStopPagination(PaginationState $state, int $teamId): bool\n {\n if ($state->hasReachedSafetyLimit()) {\n $this->logger->warning('[Hubspot] Reached maximum request limit during pagination', [\n 'team_id' => $teamId,\n 'safety_limit' => PaginationConfig::LOOP_SAFETY_LIMIT,\n 'total_fetched' => $state->totalRecords,\n ]);\n\n return true;\n }\n\n return false;\n }\n\n private function handlePaginationStrategy(\n array $payload,\n array $defaultFilter,\n PaginationState $state,\n int $resultsPerPage,\n int $teamId\n ): array {\n if ($this->shouldSwitchToKeysetPagination($state, $resultsPerPage)) {\n $payload['filters'] = $defaultFilter;\n $payload['filters'][] = [\n 'propertyName' => 'hs_object_id',\n 'operator' => 'LT',\n 'value' => $state->lastRecordId,\n ];\n\n $this->logger->info('[Hubspot] Search keyset pagination request', [\n 'team_id' => $teamId,\n 'sequence' => $state->requestCount,\n 'itemsPerPage' => $resultsPerPage,\n 'payload' => $payload,\n 'total' => $state->total,\n ]);\n\n unset($payload['after']);\n $state->setOffset(0);\n }\n\n if ($state->offset) {\n $payload['after'] = $state->offset;\n }\n\n return $payload;\n }\n\n private function shouldSwitchToKeysetPagination(PaginationState $state, int $resultsPerPage): bool\n {\n // Check if we've hit the offset limit\n $shouldSwitch = $state->requestCount > 0 && ($state->offset + $resultsPerPage) > PaginationConfig::TOTAL_QUERY_LIMIT;\n\n if ($shouldSwitch && $state->lastRecordId === null) {\n $this->logger->warning('[Hubspot] Cannot switch to keyset pagination: lastRecordId is null', [\n 'request_count' => $state->requestCount,\n 'current_offset' => $state->offset,\n 'results_per_page' => $resultsPerPage,\n 'total_query_limit' => PaginationConfig::TOTAL_QUERY_LIMIT,\n ]);\n\n return false; // Continue with offset pagination\n }\n\n return $shouldSwitch;\n }\n\n private function validateTokenIfNeeded(Client $client, PaginationState $state): void\n {\n if ($state->shouldValidateToken()) {\n $client->ensureValidToken();\n $state->updateLastTokenCheck();\n }\n }\n\n private function executeSearchRequest(Client $client, string $objectType, array $payload, PaginationState $state): array\n {\n try {\n return $client->search($objectType, $payload);\n } catch (\\Exception $e) {\n if ($client->isUnauthorizedException($e)) {\n $this->logger->warning('[Hubspot] Got 401 during pagination, attempting token refresh', [\n 'team_id' => $client->getConfig()->getTeam()->getId(),\n 'error' => $e->getMessage(),\n ]);\n\n $client->ensureValidToken();\n $state->updateLastTokenCheck();\n\n try {\n $result = $client->search($objectType, $payload);\n\n $this->logger->info('[Hubspot] Token refresh and retry successful', [\n 'team_id' => $client->getConfig()->getTeam()->getId(),\n ]);\n\n return $result;\n } catch (\\Exception $retryException) {\n $this->logger->error('[Hubspot] Retry request failed after token refresh', [\n 'team_id' => $client->getConfig()->getTeam()->getId(),\n 'original_error' => $e->getMessage(),\n 'retry_error' => $retryException->getMessage(),\n ]);\n\n throw $retryException;\n }\n }\n\n // RateLimitException and other exceptions are re-thrown as-is\n throw $e;\n }\n }\n\n private function updateLastRecordId(array $page, PaginationState $state): void\n {\n $lastRecord = ! empty($page['results']) ? end($page['results']) : null;\n $lastRecordId = $lastRecord['id'] ?? null;\n $state->updateLastRecordId($lastRecordId);\n }\n\n private function getNextOffset(array $page): int\n {\n return isset($page['paging']['next']['after']) ? (int) $page['paging']['next']['after'] : 0;\n }\n\n private function logPaginationProgress(PaginationState $state, int $teamId, string $endpoint): void\n {\n if ($state->shouldLogProgress()) {\n $this->logger->info('[Hubspot] Pagination progress log', [\n 'team_id' => $teamId,\n 'endpoint' => $endpoint,\n 'requests_made' => $state->requestCount,\n 'records_fetched' => $state->totalRecords,\n 'elapsed_seconds' => $state->getElapsedSeconds(),\n ]);\n }\n }\n\n private function calculateDelayInMicroseconds(): int\n {\n return (int) (1 / PaginationConfig::SEARCH_RPS_LIMIT * 1000000);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot\\Pagination;\n\nuse Jiminny\\Services\\Crm\\Hubspot\\Client;\nuse Jiminny\\Services\\Crm\\Hubspot\\PayloadBuilder;\nuse Psr\\Log\\LoggerInterface;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\n\nclass HubspotPaginationService\n{\n public function __construct(\n private LoggerInterface $logger\n ) {\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n Client $client,\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n $state = new PaginationState(offset: $offset);\n $endpoint = Client::BASE_URL . \"/crm/v3/objects/{$type}/search\";\n $defaultFilter = $payload['filters'] ?? [];\n $resultsPerPage = PayloadBuilder::MAX_SEARCH_REQUEST_LIMIT;\n $teamId = $client->getConfig()->getTeam()->getId();\n $delay = $this->calculateDelayInMicroseconds();\n\n do {\n if ($this->shouldStopPagination($state, $teamId)) {\n break;\n }\n\n $payload = $this->handlePaginationStrategy($payload, $defaultFilter, $state, $resultsPerPage, $teamId);\n\n $this->validateTokenIfNeeded($client, $state);\n if ($state->requestCount > 0) {\n usleep($delay);\n }\n\n $page = $this->executeSearchRequest($client, $type, $payload, $state);\n\n $state->setTotal($page['total'] ?? 0);\n $this->updateLastRecordId($page, $state);\n\n // Safely iterate over results with null check\n $results = $page['results'] ?? [];\n foreach ($results as $row) {\n $state->incrementTotalRecords();\n yield $row;\n }\n\n $state->setOffset($this->getNextOffset($page));\n $state->incrementRequestCount();\n\n $this->logPaginationProgress($state, $teamId, $endpoint);\n } while ($state->offset && ! empty($page['results']));\n\n // Log final pagination completion stats\n $this->logger->info('[Hubspot] Pagination completed', [\n 'team_id' => $teamId,\n 'endpoint' => $endpoint,\n 'total_requests' => $state->requestCount,\n 'total_records_fetched' => $state->totalRecords,\n 'total_elapsed_seconds' => round($state->getElapsedSeconds(), 2),\n 'average_seconds_per_request' => $state->requestCount > 0 ? round($state->getElapsedSeconds() / $state->requestCount, 2) : 0,\n ]);\n\n // Update reference parameters\n $total = $state->total;\n $lastRecordId = $state->lastRecordId;\n }\n\n private function shouldStopPagination(PaginationState $state, int $teamId): bool\n {\n if ($state->hasReachedSafetyLimit()) {\n $this->logger->warning('[Hubspot] Reached maximum request limit during pagination', [\n 'team_id' => $teamId,\n 'safety_limit' => PaginationConfig::LOOP_SAFETY_LIMIT,\n 'total_fetched' => $state->totalRecords,\n ]);\n\n return true;\n }\n\n return false;\n }\n\n private function handlePaginationStrategy(\n array $payload,\n array $defaultFilter,\n PaginationState $state,\n int $resultsPerPage,\n int $teamId\n ): array {\n if ($this->shouldSwitchToKeysetPagination($state, $resultsPerPage)) {\n $payload['filters'] = $defaultFilter;\n $payload['filters'][] = [\n 'propertyName' => 'hs_object_id',\n 'operator' => 'LT',\n 'value' => $state->lastRecordId,\n ];\n\n $this->logger->info('[Hubspot] Search keyset pagination request', [\n 'team_id' => $teamId,\n 'sequence' => $state->requestCount,\n 'itemsPerPage' => $resultsPerPage,\n 'payload' => $payload,\n 'total' => $state->total,\n ]);\n\n unset($payload['after']);\n $state->setOffset(0);\n }\n\n if ($state->offset) {\n $payload['after'] = $state->offset;\n }\n\n return $payload;\n }\n\n private function shouldSwitchToKeysetPagination(PaginationState $state, int $resultsPerPage): bool\n {\n // Check if we've hit the offset limit\n $shouldSwitch = $state->requestCount > 0 && ($state->offset + $resultsPerPage) > PaginationConfig::TOTAL_QUERY_LIMIT;\n\n if ($shouldSwitch && $state->lastRecordId === null) {\n $this->logger->warning('[Hubspot] Cannot switch to keyset pagination: lastRecordId is null', [\n 'request_count' => $state->requestCount,\n 'current_offset' => $state->offset,\n 'results_per_page' => $resultsPerPage,\n 'total_query_limit' => PaginationConfig::TOTAL_QUERY_LIMIT,\n ]);\n\n return false; // Continue with offset pagination\n }\n\n return $shouldSwitch;\n }\n\n private function validateTokenIfNeeded(Client $client, PaginationState $state): void\n {\n if ($state->shouldValidateToken()) {\n $client->ensureValidToken();\n $state->updateLastTokenCheck();\n }\n }\n\n private function executeSearchRequest(Client $client, string $objectType, array $payload, PaginationState $state): array\n {\n try {\n return $client->search($objectType, $payload);\n } catch (\\Exception $e) {\n if ($client->isUnauthorizedException($e)) {\n $this->logger->warning('[Hubspot] Got 401 during pagination, attempting token refresh', [\n 'team_id' => $client->getConfig()->getTeam()->getId(),\n 'error' => $e->getMessage(),\n ]);\n\n $client->ensureValidToken();\n $state->updateLastTokenCheck();\n\n try {\n $result = $client->search($objectType, $payload);\n\n $this->logger->info('[Hubspot] Token refresh and retry successful', [\n 'team_id' => $client->getConfig()->getTeam()->getId(),\n ]);\n\n return $result;\n } catch (\\Exception $retryException) {\n $this->logger->error('[Hubspot] Retry request failed after token refresh', [\n 'team_id' => $client->getConfig()->getTeam()->getId(),\n 'original_error' => $e->getMessage(),\n 'retry_error' => $retryException->getMessage(),\n ]);\n\n throw $retryException;\n }\n }\n\n // RateLimitException and other exceptions are re-thrown as-is\n throw $e;\n }\n }\n\n private function updateLastRecordId(array $page, PaginationState $state): void\n {\n $lastRecord = ! empty($page['results']) ? end($page['results']) : null;\n $lastRecordId = $lastRecord['id'] ?? null;\n $state->updateLastRecordId($lastRecordId);\n }\n\n private function getNextOffset(array $page): int\n {\n return isset($page['paging']['next']['after']) ? (int) $page['paging']['next']['after'] : 0;\n }\n\n private function logPaginationProgress(PaginationState $state, int $teamId, string $endpoint): void\n {\n if ($state->shouldLogProgress()) {\n $this->logger->info('[Hubspot] Pagination progress log', [\n 'team_id' => $teamId,\n 'endpoint' => $endpoint,\n 'requests_made' => $state->requestCount,\n 'records_fetched' => $state->totalRecords,\n 'elapsed_seconds' => $state->getElapsedSeconds(),\n ]);\n }\n }\n\n private function calculateDelayInMicroseconds(): int\n {\n return (int) (1 / PaginationConfig::SEARCH_RPS_LIMIT * 1000000);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"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":"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}]...
|
-8071999187288209021
|
-5733694816344952341
|
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
12
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot\Pagination;
use Jiminny\Services\Crm\Hubspot\Client;
use Jiminny\Services\Crm\Hubspot\PayloadBuilder;
use Psr\Log\LoggerInterface;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
class HubspotPaginationService
{
public function __construct(
private LoggerInterface $logger
) {
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
Client $client,
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
$state = new PaginationState(offset: $offset);
$endpoint = Client::BASE_URL . "/crm/v3/objects/{$type}/search";
$defaultFilter = $payload['filters'] ?? [];
$resultsPerPage = PayloadBuilder::MAX_SEARCH_REQUEST_LIMIT;
$teamId = $client->getConfig()->getTeam()->getId();
$delay = $this->calculateDelayInMicroseconds();
do {
if ($this->shouldStopPagination($state, $teamId)) {
break;
}
$payload = $this->handlePaginationStrategy($payload, $defaultFilter, $state, $resultsPerPage, $teamId);
$this->validateTokenIfNeeded($client, $state);
if ($state->requestCount > 0) {
usleep($delay);
}
$page = $this->executeSearchRequest($client, $type, $payload, $state);
$state->setTotal($page['total'] ?? 0);
$this->updateLastRecordId($page, $state);
// Safely iterate over results with null check
$results = $page['results'] ?? [];
foreach ($results as $row) {
$state->incrementTotalRecords();
yield $row;
}
$state->setOffset($this->getNextOffset($page));
$state->incrementRequestCount();
$this->logPaginationProgress($state, $teamId, $endpoint);
} while ($state->offset && ! empty($page['results']));
// Log final pagination completion stats
$this->logger->info('[Hubspot] Pagination completed', [
'team_id' => $teamId,
'endpoint' => $endpoint,
'total_requests' => $state->requestCount,
'total_records_fetched' => $state->totalRecords,
'total_elapsed_seconds' => round($state->getElapsedSeconds(), 2),
'average_seconds_per_request' => $state->requestCount > 0 ? round($state->getElapsedSeconds() / $state->requestCount, 2) : 0,
]);
// Update reference parameters
$total = $state->total;
$lastRecordId = $state->lastRecordId;
}
private function shouldStopPagination(PaginationState $state, int $teamId): bool
{
if ($state->hasReachedSafetyLimit()) {
$this->logger->warning('[Hubspot] Reached maximum request limit during pagination', [
'team_id' => $teamId,
'safety_limit' => PaginationConfig::LOOP_SAFETY_LIMIT,
'total_fetched' => $state->totalRecords,
]);
return true;
}
return false;
}
private function handlePaginationStrategy(
array $payload,
array $defaultFilter,
PaginationState $state,
int $resultsPerPage,
int $teamId
): array {
if ($this->shouldSwitchToKeysetPagination($state, $resultsPerPage)) {
$payload['filters'] = $defaultFilter;
$payload['filters'][] = [
'propertyName' => 'hs_object_id',
'operator' => 'LT',
'value' => $state->lastRecordId,
];
$this->logger->info('[Hubspot] Search keyset pagination request', [
'team_id' => $teamId,
'sequence' => $state->requestCount,
'itemsPerPage' => $resultsPerPage,
'payload' => $payload,
'total' => $state->total,
]);
unset($payload['after']);
$state->setOffset(0);
}
if ($state->offset) {
$payload['after'] = $state->offset;
}
return $payload;
}
private function shouldSwitchToKeysetPagination(PaginationState $state, int $resultsPerPage): bool
{
// Check if we've hit the offset limit
$shouldSwitch = $state->requestCount > 0 && ($state->offset + $resultsPerPage) > PaginationConfig::TOTAL_QUERY_LIMIT;
if ($shouldSwitch && $state->lastRecordId === null) {
$this->logger->warning('[Hubspot] Cannot switch to keyset pagination: lastRecordId is null', [
'request_count' => $state->requestCount,
'current_offset' => $state->offset,
'results_per_page' => $resultsPerPage,
'total_query_limit' => PaginationConfig::TOTAL_QUERY_LIMIT,
]);
return false; // Continue with offset pagination
}
return $shouldSwitch;
}
private function validateTokenIfNeeded(Client $client, PaginationState $state): void
{
if ($state->shouldValidateToken()) {
$client->ensureValidToken();
$state->updateLastTokenCheck();
}
}
private function executeSearchRequest(Client $client, string $objectType, array $payload, PaginationState $state): array
{
try {
return $client->search($objectType, $payload);
} catch (\Exception $e) {
if ($client->isUnauthorizedException($e)) {
$this->logger->warning('[Hubspot] Got 401 during pagination, attempting token refresh', [
'team_id' => $client->getConfig()->getTeam()->getId(),
'error' => $e->getMessage(),
]);
$client->ensureValidToken();
$state->updateLastTokenCheck();
try {
$result = $client->search($objectType, $payload);
$this->logger->info('[Hubspot] Token refresh and retry successful', [
'team_id' => $client->getConfig()->getTeam()->getId(),
]);
return $result;
} catch (\Exception $retryException) {
$this->logger->error('[Hubspot] Retry request failed after token refresh', [
'team_id' => $client->getConfig()->getTeam()->getId(),
'original_error' => $e->getMessage(),
'retry_error' => $retryException->getMessage(),
]);
throw $retryException;
}
}
// RateLimitException and other exceptions are re-thrown as-is
throw $e;
}
}
private function updateLastRecordId(array $page, PaginationState $state): void
{
$lastRecord = ! empty($page['results']) ? end($page['results']) : null;
$lastRecordId = $lastRecord['id'] ?? null;
$state->updateLastRecordId($lastRecordId);
}
private function getNextOffset(array $page): int
{
return isset($page['paging']['next']['after']) ? (int) $page['paging']['next']['after'] : 0;
}
private function logPaginationProgress(PaginationState $state, int $teamId, string $endpoint): void
{
if ($state->shouldLogProgress()) {
$this->logger->info('[Hubspot] Pagination progress log', [
'team_id' => $teamId,
'endpoint' => $endpoint,
'requests_made' => $state->requestCount,
'records_fetched' => $state->totalRecords,
'elapsed_seconds' => $state->getElapsedSeconds(),
]);
}
}
private function calculateDelayInMicroseconds(): int
{
return (int) (1 / PaginationConfig::SEARCH_RPS_LIMIT * 1000000);
}
}
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"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
15796
|
698
|
12
|
2026-05-11T07:16:45.019289+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778483805019_m1.jpg...
|
PhpStorm
|
faVsco.js – HubspotPaginationService.php
|
True
|
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
12
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot\Pagination;
use Jiminny\Services\Crm\Hubspot\Client;
use Jiminny\Services\Crm\Hubspot\PayloadBuilder;
use Psr\Log\LoggerInterface;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
class HubspotPaginationService
{
public function __construct(
private LoggerInterface $logger
) {
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
Client $client,
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
$state = new PaginationState(offset: $offset);
$endpoint = Client::BASE_URL . "/crm/v3/objects/{$type}/search";
$defaultFilter = $payload['filters'] ?? [];
$resultsPerPage = PayloadBuilder::MAX_SEARCH_REQUEST_LIMIT;
$teamId = $client->getConfig()->getTeam()->getId();
$delay = $this->calculateDelayInMicroseconds();
do {
if ($this->shouldStopPagination($state, $teamId)) {
break;
}
$payload = $this->handlePaginationStrategy($payload, $defaultFilter, $state, $resultsPerPage, $teamId);
$this->validateTokenIfNeeded($client, $state);
if ($state->requestCount > 0) {
usleep($delay);
}
$page = $this->executeSearchRequest($client, $type, $payload, $state);
$state->setTotal($page['total'] ?? 0);
$this->updateLastRecordId($page, $state);
// Safely iterate over results with null check
$results = $page['results'] ?? [];
foreach ($results as $row) {
$state->incrementTotalRecords();
yield $row;
}
$state->setOffset($this->getNextOffset($page));
$state->incrementRequestCount();
$this->logPaginationProgress($state, $teamId, $endpoint);
} while ($state->offset && ! empty($page['results']));
// Log final pagination completion stats
$this->logger->info('[Hubspot] Pagination completed', [
'team_id' => $teamId,
'endpoint' => $endpoint,
'total_requests' => $state->requestCount,
'total_records_fetched' => $state->totalRecords,
'total_elapsed_seconds' => round($state->getElapsedSeconds(), 2),
'average_seconds_per_request' => $state->requestCount > 0 ? round($state->getElapsedSeconds() / $state->requestCount, 2) : 0,
]);
// Update reference parameters
$total = $state->total;
$lastRecordId = $state->lastRecordId;
}
private function shouldStopPagination(PaginationState $state, int $teamId): bool
{
if ($state->hasReachedSafetyLimit()) {
$this->logger->warning('[Hubspot] Reached maximum request limit during pagination', [
'team_id' => $teamId,
'safety_limit' => PaginationConfig::LOOP_SAFETY_LIMIT,
'total_fetched' => $state->totalRecords,
]);
return true;
}
return false;
}
private function handlePaginationStrategy(
array $payload,
array $defaultFilter,
PaginationState $state,
int $resultsPerPage,
int $teamId
): array {
if ($this->shouldSwitchToKeysetPagination($state, $resultsPerPage)) {
$payload['filters'] = $defaultFilter;
$payload['filters'][] = [
'propertyName' => 'hs_object_id',
'operator' => 'LT',
'value' => $state->lastRecordId,
];
$this->logger->info('[Hubspot] Search keyset pagination request', [
'team_id' => $teamId,
'sequence' => $state->requestCount,
'itemsPerPage' => $resultsPerPage,
'payload' => $payload,
'total' => $state->total,
]);
unset($payload['after']);
$state->setOffset(0);
}
if ($state->offset) {
$payload['after'] = $state->offset;
}
return $payload;
}
private function shouldSwitchToKeysetPagination(PaginationState $state, int $resultsPerPage): bool
{
// Check if we've hit the offset limit
$shouldSwitch = $state->requestCount > 0 && ($state->offset + $resultsPerPage) > PaginationConfig::TOTAL_QUERY_LIMIT;
if ($shouldSwitch && $state->lastRecordId === null) {
$this->logger->warning('[Hubspot] Cannot switch to keyset pagination: lastRecordId is null', [
'request_count' => $state->requestCount,
'current_offset' => $state->offset,
'results_per_page' => $resultsPerPage,
'total_query_limit' => PaginationConfig::TOTAL_QUERY_LIMIT,
]);
return false; // Continue with offset pagination
}
return $shouldSwitch;
}
private function validateTokenIfNeeded(Client $client, PaginationState $state): void
{
if ($state->shouldValidateToken()) {
$client->ensureValidToken();
$state->updateLastTokenCheck();
}
}
private function executeSearchRequest(Client $client, string $objectType, array $payload, PaginationState $state): array
{
try {
return $client->search($objectType, $payload);
} catch (\Exception $e) {
if ($client->isUnauthorizedException($e)) {
$this->logger->warning('[Hubspot] Got 401 during pagination, attempting token refresh', [
'team_id' => $client->getConfig()->getTeam()->getId(),
'error' => $e->getMessage(),
]);
$client->ensureValidToken();
$state->updateLastTokenCheck();
try {
$result = $client->search($objectType, $payload);
$this->logger->info('[Hubspot] Token refresh and retry successful', [
'team_id' => $client->getConfig()->getTeam()->getId(),
]);
return $result;
} catch (\Exception $retryException) {
$this->logger->error('[Hubspot] Retry request failed after token refresh', [
'team_id' => $client->getConfig()->getTeam()->getId(),
'original_error' => $e->getMessage(),
'retry_error' => $retryException->getMessage(),
]);
throw $retryException;
}
}
// RateLimitException and other exceptions are re-thrown as-is
throw $e;
}
}
private function updateLastRecordId(array $page, PaginationState $state): void
{
$lastRecord = ! empty($page['results']) ? end($page['results']) : null;
$lastRecordId = $lastRecord['id'] ?? null;
$state->updateLastRecordId($lastRecordId);
}
private function getNextOffset(array $page): int
{
return isset($page['paging']['next']['after']) ? (int) $page['paging']['next']['after'] : 0;
}
private function logPaginationProgress(PaginationState $state, int $teamId, string $endpoint): void
{
if ($state->shouldLogProgress()) {
$this->logger->info('[Hubspot] Pagination progress log', [
'team_id' => $teamId,
'endpoint' => $endpoint,
'requests_made' => $state->requestCount,
'records_fetched' => $state->totalRecords,
'elapsed_seconds' => $state->getElapsedSeconds(),
]);
}
}
private function calculateDelayInMicroseconds(): int
{
return (int) (1 / PaginationConfig::SEARCH_RPS_LIMIT * 1000000);
}
}
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"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options...
|
[{"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":"12","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\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot\\Pagination;\n\nuse Jiminny\\Services\\Crm\\Hubspot\\Client;\nuse Jiminny\\Services\\Crm\\Hubspot\\PayloadBuilder;\nuse Psr\\Log\\LoggerInterface;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\n\nclass HubspotPaginationService\n{\n public function __construct(\n private LoggerInterface $logger\n ) {\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n Client $client,\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n $state = new PaginationState(offset: $offset);\n $endpoint = Client::BASE_URL . \"/crm/v3/objects/{$type}/search\";\n $defaultFilter = $payload['filters'] ?? [];\n $resultsPerPage = PayloadBuilder::MAX_SEARCH_REQUEST_LIMIT;\n $teamId = $client->getConfig()->getTeam()->getId();\n $delay = $this->calculateDelayInMicroseconds();\n\n do {\n if ($this->shouldStopPagination($state, $teamId)) {\n break;\n }\n\n $payload = $this->handlePaginationStrategy($payload, $defaultFilter, $state, $resultsPerPage, $teamId);\n\n $this->validateTokenIfNeeded($client, $state);\n if ($state->requestCount > 0) {\n usleep($delay);\n }\n\n $page = $this->executeSearchRequest($client, $type, $payload, $state);\n\n $state->setTotal($page['total'] ?? 0);\n $this->updateLastRecordId($page, $state);\n\n // Safely iterate over results with null check\n $results = $page['results'] ?? [];\n foreach ($results as $row) {\n $state->incrementTotalRecords();\n yield $row;\n }\n\n $state->setOffset($this->getNextOffset($page));\n $state->incrementRequestCount();\n\n $this->logPaginationProgress($state, $teamId, $endpoint);\n } while ($state->offset && ! empty($page['results']));\n\n // Log final pagination completion stats\n $this->logger->info('[Hubspot] Pagination completed', [\n 'team_id' => $teamId,\n 'endpoint' => $endpoint,\n 'total_requests' => $state->requestCount,\n 'total_records_fetched' => $state->totalRecords,\n 'total_elapsed_seconds' => round($state->getElapsedSeconds(), 2),\n 'average_seconds_per_request' => $state->requestCount > 0 ? round($state->getElapsedSeconds() / $state->requestCount, 2) : 0,\n ]);\n\n // Update reference parameters\n $total = $state->total;\n $lastRecordId = $state->lastRecordId;\n }\n\n private function shouldStopPagination(PaginationState $state, int $teamId): bool\n {\n if ($state->hasReachedSafetyLimit()) {\n $this->logger->warning('[Hubspot] Reached maximum request limit during pagination', [\n 'team_id' => $teamId,\n 'safety_limit' => PaginationConfig::LOOP_SAFETY_LIMIT,\n 'total_fetched' => $state->totalRecords,\n ]);\n\n return true;\n }\n\n return false;\n }\n\n private function handlePaginationStrategy(\n array $payload,\n array $defaultFilter,\n PaginationState $state,\n int $resultsPerPage,\n int $teamId\n ): array {\n if ($this->shouldSwitchToKeysetPagination($state, $resultsPerPage)) {\n $payload['filters'] = $defaultFilter;\n $payload['filters'][] = [\n 'propertyName' => 'hs_object_id',\n 'operator' => 'LT',\n 'value' => $state->lastRecordId,\n ];\n\n $this->logger->info('[Hubspot] Search keyset pagination request', [\n 'team_id' => $teamId,\n 'sequence' => $state->requestCount,\n 'itemsPerPage' => $resultsPerPage,\n 'payload' => $payload,\n 'total' => $state->total,\n ]);\n\n unset($payload['after']);\n $state->setOffset(0);\n }\n\n if ($state->offset) {\n $payload['after'] = $state->offset;\n }\n\n return $payload;\n }\n\n private function shouldSwitchToKeysetPagination(PaginationState $state, int $resultsPerPage): bool\n {\n // Check if we've hit the offset limit\n $shouldSwitch = $state->requestCount > 0 && ($state->offset + $resultsPerPage) > PaginationConfig::TOTAL_QUERY_LIMIT;\n\n if ($shouldSwitch && $state->lastRecordId === null) {\n $this->logger->warning('[Hubspot] Cannot switch to keyset pagination: lastRecordId is null', [\n 'request_count' => $state->requestCount,\n 'current_offset' => $state->offset,\n 'results_per_page' => $resultsPerPage,\n 'total_query_limit' => PaginationConfig::TOTAL_QUERY_LIMIT,\n ]);\n\n return false; // Continue with offset pagination\n }\n\n return $shouldSwitch;\n }\n\n private function validateTokenIfNeeded(Client $client, PaginationState $state): void\n {\n if ($state->shouldValidateToken()) {\n $client->ensureValidToken();\n $state->updateLastTokenCheck();\n }\n }\n\n private function executeSearchRequest(Client $client, string $objectType, array $payload, PaginationState $state): array\n {\n try {\n return $client->search($objectType, $payload);\n } catch (\\Exception $e) {\n if ($client->isUnauthorizedException($e)) {\n $this->logger->warning('[Hubspot] Got 401 during pagination, attempting token refresh', [\n 'team_id' => $client->getConfig()->getTeam()->getId(),\n 'error' => $e->getMessage(),\n ]);\n\n $client->ensureValidToken();\n $state->updateLastTokenCheck();\n\n try {\n $result = $client->search($objectType, $payload);\n\n $this->logger->info('[Hubspot] Token refresh and retry successful', [\n 'team_id' => $client->getConfig()->getTeam()->getId(),\n ]);\n\n return $result;\n } catch (\\Exception $retryException) {\n $this->logger->error('[Hubspot] Retry request failed after token refresh', [\n 'team_id' => $client->getConfig()->getTeam()->getId(),\n 'original_error' => $e->getMessage(),\n 'retry_error' => $retryException->getMessage(),\n ]);\n\n throw $retryException;\n }\n }\n\n // RateLimitException and other exceptions are re-thrown as-is\n throw $e;\n }\n }\n\n private function updateLastRecordId(array $page, PaginationState $state): void\n {\n $lastRecord = ! empty($page['results']) ? end($page['results']) : null;\n $lastRecordId = $lastRecord['id'] ?? null;\n $state->updateLastRecordId($lastRecordId);\n }\n\n private function getNextOffset(array $page): int\n {\n return isset($page['paging']['next']['after']) ? (int) $page['paging']['next']['after'] : 0;\n }\n\n private function logPaginationProgress(PaginationState $state, int $teamId, string $endpoint): void\n {\n if ($state->shouldLogProgress()) {\n $this->logger->info('[Hubspot] Pagination progress log', [\n 'team_id' => $teamId,\n 'endpoint' => $endpoint,\n 'requests_made' => $state->requestCount,\n 'records_fetched' => $state->totalRecords,\n 'elapsed_seconds' => $state->getElapsedSeconds(),\n ]);\n }\n }\n\n private function calculateDelayInMicroseconds(): int\n {\n return (int) (1 / PaginationConfig::SEARCH_RPS_LIMIT * 1000000);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot\\Pagination;\n\nuse Jiminny\\Services\\Crm\\Hubspot\\Client;\nuse Jiminny\\Services\\Crm\\Hubspot\\PayloadBuilder;\nuse Psr\\Log\\LoggerInterface;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\n\nclass HubspotPaginationService\n{\n public function __construct(\n private LoggerInterface $logger\n ) {\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n Client $client,\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n $state = new PaginationState(offset: $offset);\n $endpoint = Client::BASE_URL . \"/crm/v3/objects/{$type}/search\";\n $defaultFilter = $payload['filters'] ?? [];\n $resultsPerPage = PayloadBuilder::MAX_SEARCH_REQUEST_LIMIT;\n $teamId = $client->getConfig()->getTeam()->getId();\n $delay = $this->calculateDelayInMicroseconds();\n\n do {\n if ($this->shouldStopPagination($state, $teamId)) {\n break;\n }\n\n $payload = $this->handlePaginationStrategy($payload, $defaultFilter, $state, $resultsPerPage, $teamId);\n\n $this->validateTokenIfNeeded($client, $state);\n if ($state->requestCount > 0) {\n usleep($delay);\n }\n\n $page = $this->executeSearchRequest($client, $type, $payload, $state);\n\n $state->setTotal($page['total'] ?? 0);\n $this->updateLastRecordId($page, $state);\n\n // Safely iterate over results with null check\n $results = $page['results'] ?? [];\n foreach ($results as $row) {\n $state->incrementTotalRecords();\n yield $row;\n }\n\n $state->setOffset($this->getNextOffset($page));\n $state->incrementRequestCount();\n\n $this->logPaginationProgress($state, $teamId, $endpoint);\n } while ($state->offset && ! empty($page['results']));\n\n // Log final pagination completion stats\n $this->logger->info('[Hubspot] Pagination completed', [\n 'team_id' => $teamId,\n 'endpoint' => $endpoint,\n 'total_requests' => $state->requestCount,\n 'total_records_fetched' => $state->totalRecords,\n 'total_elapsed_seconds' => round($state->getElapsedSeconds(), 2),\n 'average_seconds_per_request' => $state->requestCount > 0 ? round($state->getElapsedSeconds() / $state->requestCount, 2) : 0,\n ]);\n\n // Update reference parameters\n $total = $state->total;\n $lastRecordId = $state->lastRecordId;\n }\n\n private function shouldStopPagination(PaginationState $state, int $teamId): bool\n {\n if ($state->hasReachedSafetyLimit()) {\n $this->logger->warning('[Hubspot] Reached maximum request limit during pagination', [\n 'team_id' => $teamId,\n 'safety_limit' => PaginationConfig::LOOP_SAFETY_LIMIT,\n 'total_fetched' => $state->totalRecords,\n ]);\n\n return true;\n }\n\n return false;\n }\n\n private function handlePaginationStrategy(\n array $payload,\n array $defaultFilter,\n PaginationState $state,\n int $resultsPerPage,\n int $teamId\n ): array {\n if ($this->shouldSwitchToKeysetPagination($state, $resultsPerPage)) {\n $payload['filters'] = $defaultFilter;\n $payload['filters'][] = [\n 'propertyName' => 'hs_object_id',\n 'operator' => 'LT',\n 'value' => $state->lastRecordId,\n ];\n\n $this->logger->info('[Hubspot] Search keyset pagination request', [\n 'team_id' => $teamId,\n 'sequence' => $state->requestCount,\n 'itemsPerPage' => $resultsPerPage,\n 'payload' => $payload,\n 'total' => $state->total,\n ]);\n\n unset($payload['after']);\n $state->setOffset(0);\n }\n\n if ($state->offset) {\n $payload['after'] = $state->offset;\n }\n\n return $payload;\n }\n\n private function shouldSwitchToKeysetPagination(PaginationState $state, int $resultsPerPage): bool\n {\n // Check if we've hit the offset limit\n $shouldSwitch = $state->requestCount > 0 && ($state->offset + $resultsPerPage) > PaginationConfig::TOTAL_QUERY_LIMIT;\n\n if ($shouldSwitch && $state->lastRecordId === null) {\n $this->logger->warning('[Hubspot] Cannot switch to keyset pagination: lastRecordId is null', [\n 'request_count' => $state->requestCount,\n 'current_offset' => $state->offset,\n 'results_per_page' => $resultsPerPage,\n 'total_query_limit' => PaginationConfig::TOTAL_QUERY_LIMIT,\n ]);\n\n return false; // Continue with offset pagination\n }\n\n return $shouldSwitch;\n }\n\n private function validateTokenIfNeeded(Client $client, PaginationState $state): void\n {\n if ($state->shouldValidateToken()) {\n $client->ensureValidToken();\n $state->updateLastTokenCheck();\n }\n }\n\n private function executeSearchRequest(Client $client, string $objectType, array $payload, PaginationState $state): array\n {\n try {\n return $client->search($objectType, $payload);\n } catch (\\Exception $e) {\n if ($client->isUnauthorizedException($e)) {\n $this->logger->warning('[Hubspot] Got 401 during pagination, attempting token refresh', [\n 'team_id' => $client->getConfig()->getTeam()->getId(),\n 'error' => $e->getMessage(),\n ]);\n\n $client->ensureValidToken();\n $state->updateLastTokenCheck();\n\n try {\n $result = $client->search($objectType, $payload);\n\n $this->logger->info('[Hubspot] Token refresh and retry successful', [\n 'team_id' => $client->getConfig()->getTeam()->getId(),\n ]);\n\n return $result;\n } catch (\\Exception $retryException) {\n $this->logger->error('[Hubspot] Retry request failed after token refresh', [\n 'team_id' => $client->getConfig()->getTeam()->getId(),\n 'original_error' => $e->getMessage(),\n 'retry_error' => $retryException->getMessage(),\n ]);\n\n throw $retryException;\n }\n }\n\n // RateLimitException and other exceptions are re-thrown as-is\n throw $e;\n }\n }\n\n private function updateLastRecordId(array $page, PaginationState $state): void\n {\n $lastRecord = ! empty($page['results']) ? end($page['results']) : null;\n $lastRecordId = $lastRecord['id'] ?? null;\n $state->updateLastRecordId($lastRecordId);\n }\n\n private function getNextOffset(array $page): int\n {\n return isset($page['paging']['next']['after']) ? (int) $page['paging']['next']['after'] : 0;\n }\n\n private function logPaginationProgress(PaginationState $state, int $teamId, string $endpoint): void\n {\n if ($state->shouldLogProgress()) {\n $this->logger->info('[Hubspot] Pagination progress log', [\n 'team_id' => $teamId,\n 'endpoint' => $endpoint,\n 'requests_made' => $state->requestCount,\n 'records_fetched' => $state->totalRecords,\n 'elapsed_seconds' => $state->getElapsedSeconds(),\n ]);\n }\n }\n\n private function calculateDelayInMicroseconds(): int\n {\n return (int) (1 / PaginationConfig::SEARCH_RPS_LIMIT * 1000000);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"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":"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}]...
|
-8071999187288209021
|
-5733694816344952341
|
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
12
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot\Pagination;
use Jiminny\Services\Crm\Hubspot\Client;
use Jiminny\Services\Crm\Hubspot\PayloadBuilder;
use Psr\Log\LoggerInterface;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
class HubspotPaginationService
{
public function __construct(
private LoggerInterface $logger
) {
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
Client $client,
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
$state = new PaginationState(offset: $offset);
$endpoint = Client::BASE_URL . "/crm/v3/objects/{$type}/search";
$defaultFilter = $payload['filters'] ?? [];
$resultsPerPage = PayloadBuilder::MAX_SEARCH_REQUEST_LIMIT;
$teamId = $client->getConfig()->getTeam()->getId();
$delay = $this->calculateDelayInMicroseconds();
do {
if ($this->shouldStopPagination($state, $teamId)) {
break;
}
$payload = $this->handlePaginationStrategy($payload, $defaultFilter, $state, $resultsPerPage, $teamId);
$this->validateTokenIfNeeded($client, $state);
if ($state->requestCount > 0) {
usleep($delay);
}
$page = $this->executeSearchRequest($client, $type, $payload, $state);
$state->setTotal($page['total'] ?? 0);
$this->updateLastRecordId($page, $state);
// Safely iterate over results with null check
$results = $page['results'] ?? [];
foreach ($results as $row) {
$state->incrementTotalRecords();
yield $row;
}
$state->setOffset($this->getNextOffset($page));
$state->incrementRequestCount();
$this->logPaginationProgress($state, $teamId, $endpoint);
} while ($state->offset && ! empty($page['results']));
// Log final pagination completion stats
$this->logger->info('[Hubspot] Pagination completed', [
'team_id' => $teamId,
'endpoint' => $endpoint,
'total_requests' => $state->requestCount,
'total_records_fetched' => $state->totalRecords,
'total_elapsed_seconds' => round($state->getElapsedSeconds(), 2),
'average_seconds_per_request' => $state->requestCount > 0 ? round($state->getElapsedSeconds() / $state->requestCount, 2) : 0,
]);
// Update reference parameters
$total = $state->total;
$lastRecordId = $state->lastRecordId;
}
private function shouldStopPagination(PaginationState $state, int $teamId): bool
{
if ($state->hasReachedSafetyLimit()) {
$this->logger->warning('[Hubspot] Reached maximum request limit during pagination', [
'team_id' => $teamId,
'safety_limit' => PaginationConfig::LOOP_SAFETY_LIMIT,
'total_fetched' => $state->totalRecords,
]);
return true;
}
return false;
}
private function handlePaginationStrategy(
array $payload,
array $defaultFilter,
PaginationState $state,
int $resultsPerPage,
int $teamId
): array {
if ($this->shouldSwitchToKeysetPagination($state, $resultsPerPage)) {
$payload['filters'] = $defaultFilter;
$payload['filters'][] = [
'propertyName' => 'hs_object_id',
'operator' => 'LT',
'value' => $state->lastRecordId,
];
$this->logger->info('[Hubspot] Search keyset pagination request', [
'team_id' => $teamId,
'sequence' => $state->requestCount,
'itemsPerPage' => $resultsPerPage,
'payload' => $payload,
'total' => $state->total,
]);
unset($payload['after']);
$state->setOffset(0);
}
if ($state->offset) {
$payload['after'] = $state->offset;
}
return $payload;
}
private function shouldSwitchToKeysetPagination(PaginationState $state, int $resultsPerPage): bool
{
// Check if we've hit the offset limit
$shouldSwitch = $state->requestCount > 0 && ($state->offset + $resultsPerPage) > PaginationConfig::TOTAL_QUERY_LIMIT;
if ($shouldSwitch && $state->lastRecordId === null) {
$this->logger->warning('[Hubspot] Cannot switch to keyset pagination: lastRecordId is null', [
'request_count' => $state->requestCount,
'current_offset' => $state->offset,
'results_per_page' => $resultsPerPage,
'total_query_limit' => PaginationConfig::TOTAL_QUERY_LIMIT,
]);
return false; // Continue with offset pagination
}
return $shouldSwitch;
}
private function validateTokenIfNeeded(Client $client, PaginationState $state): void
{
if ($state->shouldValidateToken()) {
$client->ensureValidToken();
$state->updateLastTokenCheck();
}
}
private function executeSearchRequest(Client $client, string $objectType, array $payload, PaginationState $state): array
{
try {
return $client->search($objectType, $payload);
} catch (\Exception $e) {
if ($client->isUnauthorizedException($e)) {
$this->logger->warning('[Hubspot] Got 401 during pagination, attempting token refresh', [
'team_id' => $client->getConfig()->getTeam()->getId(),
'error' => $e->getMessage(),
]);
$client->ensureValidToken();
$state->updateLastTokenCheck();
try {
$result = $client->search($objectType, $payload);
$this->logger->info('[Hubspot] Token refresh and retry successful', [
'team_id' => $client->getConfig()->getTeam()->getId(),
]);
return $result;
} catch (\Exception $retryException) {
$this->logger->error('[Hubspot] Retry request failed after token refresh', [
'team_id' => $client->getConfig()->getTeam()->getId(),
'original_error' => $e->getMessage(),
'retry_error' => $retryException->getMessage(),
]);
throw $retryException;
}
}
// RateLimitException and other exceptions are re-thrown as-is
throw $e;
}
}
private function updateLastRecordId(array $page, PaginationState $state): void
{
$lastRecord = ! empty($page['results']) ? end($page['results']) : null;
$lastRecordId = $lastRecord['id'] ?? null;
$state->updateLastRecordId($lastRecordId);
}
private function getNextOffset(array $page): int
{
return isset($page['paging']['next']['after']) ? (int) $page['paging']['next']['after'] : 0;
}
private function logPaginationProgress(PaginationState $state, int $teamId, string $endpoint): void
{
if ($state->shouldLogProgress()) {
$this->logger->info('[Hubspot] Pagination progress log', [
'team_id' => $teamId,
'endpoint' => $endpoint,
'requests_made' => $state->requestCount,
'records_fetched' => $state->totalRecords,
'elapsed_seconds' => $state->getElapsedSeconds(),
]);
}
}
private function calculateDelayInMicroseconds(): int
{
return (int) (1 / PaginationConfig::SEARCH_RPS_LIMIT * 1000000);
}
}
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"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options...
|
15792
|
NULL
|
NULL
|
NULL
|
|
15701
|
697
|
7
|
2026-05-11T07:09:06.614258+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778483346614_m2.jpg...
|
PhpStorm
|
Shelve Changes
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhostormINavicarecodeProletey© BatchSyncCollectore PhostormINavicarecodeProletey© BatchSyncCollectore balchsynckealsse© HubspotSyncStrategyBase.php© SyncRelatedActivityManager.phpCachedcrmservicebecorator.pnp© ProspectCache.phpo closedDealstagessDealrielasservice.gc)Decorateacuivilv.or© FieldDefinitions.phpC) FieldT vpeconvertee Hubspotclientinterc) Hubspotlokenman© PayloadBuilder.phpC) Remotecrmobiectr© ResponseNormalizec) Service,ono© SyncFieldAction.phC) SvncRelatedActivitC) WebhookSvncBatclv O IntegrationApp> O Accessors© MatchactivityermData.png© CrmActivityService.phgclass Cllent extends Baseclient 1mpLements Hubspoououc tunction cetuwnersArchivedcoool Sarcha$owners[] = Owner: :create(Sre} catch (Throwable $e) {schis-> log->error hubspoc"result = sresulc.V D Activity/Import 1 filev©MatchCrmData.phpCrm 1 file• Middleware 1 filelCommit Messagereorder callscontinuecatch Throwable se) &Sthis->lo0->error('HubSpot Farled tov Dift935ConfigODTOD FiltersD JobsDProspectSearchStraW service lralts© DataClient.phperron => se->detllessadeoSide-by-side viewer©35f036acapo/Joos/activity/lmoolmatchummbata.ongDo notignoreHighlight woras® Current versionI):return [];$this->logMessage('Resolving CRM objects');$rateLimiter->incrementRequestCount($activity$crmObjects = $crm0bjectsResolver->resolveFro112 Ereturn $owners;Console x1140Local ChangesChanges 11 tiles= env.locall ano© Client.php app/Services/Crm/HubspotC) HandleHlubsootRateLimit.oho aoo/.lobs/Middleware© HubspotClientinterface.php app/Services/Crm/Hubspot© HubspotPaginationService.php app/Services/Crm/Hubspot/Pagination© JiminnyDebugCommand.php app/Console/Commandsphe logging.php config©MatchActivityCrmData.php app/Jobs/Crm© MatchCrmData.php app/Jobs/Activity/Import© PaginationState.php app/Services/Crm/Hubspot/Pagination© RateLimitException.php app/Exceptions~ Unversioned Files 9 filesE.env.nikilocal appE .env.other app© CanAccessAiReportsTest.php tests/Unit/Policies© CreateMockAskJiminnyReportResultCommand.php app/Console/Commands/RepE favicon.ico publicEids.txt aprTraw_sql_query.sql app© SimulateWebhooksCommand.php app/Console/Commands/Crm/HubspotM+ WEBHOOK_FILTERING_IMPLEMENTATION.md app8 35f036ac app/JoA,Mimif Cempty($crm0bjects)) {$this->LogMessage('Could not resolve CRM$this->reLease(3600);sth1S-SrateLimiter->incrementRequestCount(Sactivity->getCrm());->resoLverromcauusthus-›crmservice. sthis->calu:if (emptv(Scrm0biects)) {Sthis->logMessage('Could not resolve CRM objects, retrying');Sthis->release (3600)E custom.log xElaravel.logA SF jiminny@localhost]A HS_Jocal (jiminny@localhost]# console [PKob.A console [EU]A console (STAGING][2026-05-07 14:21:15] Local. INFO: [Hubspot] DEBUG Getting headers {neaders.Shelve ChangesChangelist:2 differences$this->logMessage('Resolving CRM objects');$crmObjects = $crm0bjectsResolver->resolveFroSrateLimiter->incrementRequestCount(Sactivityif Cempty($crmObjects)) {sthis-→ ogMessage ('Could not resolve CRMsunis->release souuCancelShelve ChangesDomains: preload"]np7ccb3ee3)",b7ccb3ee3"],MabeCtmOY-1778163675-1.0.1.acure; SameSite=None"],IYALsVTP0fYm32qrSDjxYE4sd2RW|Current versionhoblsuppont Dally • In4h o1m100% 28• Mon 11 May 10:09:06CascadeHubSpot Rate Limit Re+0 ..3. We just made an additional API call while already rate-limited - amplifying the pressure4. If matchByPhone returns nothing too, the activity gets persisted as "no CRM match" even though the contact exists in HubSpot. Wrong data, no signal to retry.The middleware on MatchActivityCrmData cannot help, because the 429 was already swallowed before any RateLimitException could be raised.how serious is it reallv?In practice - probably rare, but still wrong. The GET-by-email endpoint shares HubSpot's portal-wide burst quota (100/10s on Free/Starter, 150/10s on Pro+200/10s with the API add-on), which is much more generous than the search endpoint (5 RPS). 429s on this endpoint are uncommon. But:• During heavy backfills they do happen — the same worker pool that's hammering search will also be hammering getContactByEmail• When it does happen, the cost is silent data corruption (wrong CRM match) plus extra wasted API calls falling through the cascade.What you should decideGiven vour simplification (only Client::searcho raises RateLimitException, onlv MatchActivityCrmData middleware handles it, vou have two reasonableoptions:Option A - Accept the gap, document it. The PR's scope is "handle search endpoint rate limits" since that's where 429s actually hurt. Email-by-id 429s are rareand currently treated as "not found" - same as before this PR. Nothing breaks, you just don't fix this particular gap. Add a TODO/follow-up ticketOntion B - Wrao_netContactByEmaillin executeRenest@_too.Five-line chance. then the email-match.sten_would also_throw.RateldimitExcention middlewarereleases the job. This is cheap and removes the silent-corruption risk for that one method. You don't need to touch getContactById/getOpportunityById/etc.because those aren't on the MatchActivityCrmData hot path.Mwrecommendation.OptionB.tsiattinvaddiiion.that closes.the matchina cascade.stirststep.whichls.the.mostchitpath. withoutrt.theinew.midclleware missesthe most common entry point of MatchActivityCrmData's CRM lookups.O phpAsk anything (2AL)+ <> CodeClaude Opus 4.7 Medium2 differences$this->LogMessage('Resolving CRM objects');$crmObjects = $crm0bjectsResolver-›resolveFromCall($this-›crmService, $this-›call);Srateumiter->1ncrementReguestcountsactvty->oetcrmop:if Cempty($crmObjects)) €Sthis->logMessage('Could not resolve CRM objects, retrying');Sthis->release (3600)W Windsurf Teams 929:1 UTF-8 Po 4 spaces...
|
NULL
|
-8071702211693203890
|
NULL
|
click
|
ocr
|
NULL
|
PhostormINavicarecodeProletey© BatchSyncCollectore PhostormINavicarecodeProletey© BatchSyncCollectore balchsynckealsse© HubspotSyncStrategyBase.php© SyncRelatedActivityManager.phpCachedcrmservicebecorator.pnp© ProspectCache.phpo closedDealstagessDealrielasservice.gc)Decorateacuivilv.or© FieldDefinitions.phpC) FieldT vpeconvertee Hubspotclientinterc) Hubspotlokenman© PayloadBuilder.phpC) Remotecrmobiectr© ResponseNormalizec) Service,ono© SyncFieldAction.phC) SvncRelatedActivitC) WebhookSvncBatclv O IntegrationApp> O Accessors© MatchactivityermData.png© CrmActivityService.phgclass Cllent extends Baseclient 1mpLements Hubspoououc tunction cetuwnersArchivedcoool Sarcha$owners[] = Owner: :create(Sre} catch (Throwable $e) {schis-> log->error hubspoc"result = sresulc.V D Activity/Import 1 filev©MatchCrmData.phpCrm 1 file• Middleware 1 filelCommit Messagereorder callscontinuecatch Throwable se) &Sthis->lo0->error('HubSpot Farled tov Dift935ConfigODTOD FiltersD JobsDProspectSearchStraW service lralts© DataClient.phperron => se->detllessadeoSide-by-side viewer©35f036acapo/Joos/activity/lmoolmatchummbata.ongDo notignoreHighlight woras® Current versionI):return [];$this->logMessage('Resolving CRM objects');$rateLimiter->incrementRequestCount($activity$crmObjects = $crm0bjectsResolver->resolveFro112 Ereturn $owners;Console x1140Local ChangesChanges 11 tiles= env.locall ano© Client.php app/Services/Crm/HubspotC) HandleHlubsootRateLimit.oho aoo/.lobs/Middleware© HubspotClientinterface.php app/Services/Crm/Hubspot© HubspotPaginationService.php app/Services/Crm/Hubspot/Pagination© JiminnyDebugCommand.php app/Console/Commandsphe logging.php config©MatchActivityCrmData.php app/Jobs/Crm© MatchCrmData.php app/Jobs/Activity/Import© PaginationState.php app/Services/Crm/Hubspot/Pagination© RateLimitException.php app/Exceptions~ Unversioned Files 9 filesE.env.nikilocal appE .env.other app© CanAccessAiReportsTest.php tests/Unit/Policies© CreateMockAskJiminnyReportResultCommand.php app/Console/Commands/RepE favicon.ico publicEids.txt aprTraw_sql_query.sql app© SimulateWebhooksCommand.php app/Console/Commands/Crm/HubspotM+ WEBHOOK_FILTERING_IMPLEMENTATION.md app8 35f036ac app/JoA,Mimif Cempty($crm0bjects)) {$this->LogMessage('Could not resolve CRM$this->reLease(3600);sth1S-SrateLimiter->incrementRequestCount(Sactivity->getCrm());->resoLverromcauusthus-›crmservice. sthis->calu:if (emptv(Scrm0biects)) {Sthis->logMessage('Could not resolve CRM objects, retrying');Sthis->release (3600)E custom.log xElaravel.logA SF jiminny@localhost]A HS_Jocal (jiminny@localhost]# console [PKob.A console [EU]A console (STAGING][2026-05-07 14:21:15] Local. INFO: [Hubspot] DEBUG Getting headers {neaders.Shelve ChangesChangelist:2 differences$this->logMessage('Resolving CRM objects');$crmObjects = $crm0bjectsResolver->resolveFroSrateLimiter->incrementRequestCount(Sactivityif Cempty($crmObjects)) {sthis-→ ogMessage ('Could not resolve CRMsunis->release souuCancelShelve ChangesDomains: preload"]np7ccb3ee3)",b7ccb3ee3"],MabeCtmOY-1778163675-1.0.1.acure; SameSite=None"],IYALsVTP0fYm32qrSDjxYE4sd2RW|Current versionhoblsuppont Dally • In4h o1m100% 28• Mon 11 May 10:09:06CascadeHubSpot Rate Limit Re+0 ..3. We just made an additional API call while already rate-limited - amplifying the pressure4. If matchByPhone returns nothing too, the activity gets persisted as "no CRM match" even though the contact exists in HubSpot. Wrong data, no signal to retry.The middleware on MatchActivityCrmData cannot help, because the 429 was already swallowed before any RateLimitException could be raised.how serious is it reallv?In practice - probably rare, but still wrong. The GET-by-email endpoint shares HubSpot's portal-wide burst quota (100/10s on Free/Starter, 150/10s on Pro+200/10s with the API add-on), which is much more generous than the search endpoint (5 RPS). 429s on this endpoint are uncommon. But:• During heavy backfills they do happen — the same worker pool that's hammering search will also be hammering getContactByEmail• When it does happen, the cost is silent data corruption (wrong CRM match) plus extra wasted API calls falling through the cascade.What you should decideGiven vour simplification (only Client::searcho raises RateLimitException, onlv MatchActivityCrmData middleware handles it, vou have two reasonableoptions:Option A - Accept the gap, document it. The PR's scope is "handle search endpoint rate limits" since that's where 429s actually hurt. Email-by-id 429s are rareand currently treated as "not found" - same as before this PR. Nothing breaks, you just don't fix this particular gap. Add a TODO/follow-up ticketOntion B - Wrao_netContactByEmaillin executeRenest@_too.Five-line chance. then the email-match.sten_would also_throw.RateldimitExcention middlewarereleases the job. This is cheap and removes the silent-corruption risk for that one method. You don't need to touch getContactById/getOpportunityById/etc.because those aren't on the MatchActivityCrmData hot path.Mwrecommendation.OptionB.tsiattinvaddiiion.that closes.the matchina cascade.stirststep.whichls.the.mostchitpath. withoutrt.theinew.midclleware missesthe most common entry point of MatchActivityCrmData's CRM lookups.O phpAsk anything (2AL)+ <> CodeClaude Opus 4.7 Medium2 differences$this->LogMessage('Resolving CRM objects');$crmObjects = $crm0bjectsResolver-›resolveFromCall($this-›crmService, $this-›call);Srateumiter->1ncrementReguestcountsactvty->oetcrmop:if Cempty($crmObjects)) €Sthis->logMessage('Could not resolve CRM objects, retrying');Sthis->release (3600)W Windsurf Teams 929:1 UTF-8 Po 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
15773
|
698
|
0
|
2026-05-11T07:13:54.547836+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778483634547_m1.jpg...
|
Notion Calendar
|
NULL
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Firefox FileEditViewHistoryBookmarksProfilesToolsW Firefox FileEditViewHistoryBookmarksProfilesToolsWindowHelp<DEV (docker)• жз• Support Daily • in 4h 47 mDOCKERO 81DEV (docker)882APP (-zsh)masterJY-20818-move-AJ-reports-to-separated-datadog-metricJY-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] laysJY-20698-fix-SF-activity-types-on-new-playbookJY-20543-AJ-report-trackingJY-20384-handle-auto-sync-with-no-access-to-event-typeJY-20458-ask-Jiminny-user-definitionsJY-19666-fix-import-contacts-account-associationJY-19666-HS-import-contacts-and-accounts-batch-jobJY-20458-Ask-Jiminny-ReportsJY-20200-batch-update-CRM-objects-SalesforceJY-19666-HS-webhooks-add-contact-and-companyJY-20348-trigger-setup-DI-layout-on-team-creationJY-20326-refactor-info-message-in-commandJY-20317-fix-auto-log-delay-issue-on-all-channels-disabledJY-20312-remove-on-update-change-last-synced-at-crm-configurationsJY-20306-SF-skip-auto-sync-for-task-based-playbookJY-20192-remove-deleted-team-from-saved-search-filtersJY-20197-import-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-1f-autologJY-20132-fix-note-encodingJY-19792-clean-logslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-limit) $ devroot@docker_lamp_1:/home/jiminny# ]-zsh84-zsh885100% <78• Mon 11 May 10:13:54181screenpipe"0 ₴6DEV...
|
NULL
|
-8071153140656905152
|
NULL
|
idle
|
ocr
|
NULL
|
Firefox FileEditViewHistoryBookmarksProfilesToolsW Firefox FileEditViewHistoryBookmarksProfilesToolsWindowHelp<DEV (docker)• жз• Support Daily • in 4h 47 mDOCKERO 81DEV (docker)882APP (-zsh)masterJY-20818-move-AJ-reports-to-separated-datadog-metricJY-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] laysJY-20698-fix-SF-activity-types-on-new-playbookJY-20543-AJ-report-trackingJY-20384-handle-auto-sync-with-no-access-to-event-typeJY-20458-ask-Jiminny-user-definitionsJY-19666-fix-import-contacts-account-associationJY-19666-HS-import-contacts-and-accounts-batch-jobJY-20458-Ask-Jiminny-ReportsJY-20200-batch-update-CRM-objects-SalesforceJY-19666-HS-webhooks-add-contact-and-companyJY-20348-trigger-setup-DI-layout-on-team-creationJY-20326-refactor-info-message-in-commandJY-20317-fix-auto-log-delay-issue-on-all-channels-disabledJY-20312-remove-on-update-change-last-synced-at-crm-configurationsJY-20306-SF-skip-auto-sync-for-task-based-playbookJY-20192-remove-deleted-team-from-saved-search-filtersJY-20197-import-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-1f-autologJY-20132-fix-note-encodingJY-19792-clean-logslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-limit) $ devroot@docker_lamp_1:/home/jiminny# ]-zsh84-zsh885100% <78• Mon 11 May 10:13:54181screenpipe"0 ₴6DEV...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
14481
|
643
|
39
|
2026-05-09T18:00:46.157832+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-09/1778 /Users/lukas/.screenpipe/data/data/2026-05-09/1778349646157_m1.jpg...
|
iTerm2
|
NULL
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
CodeFileEditSelectionView→Nginx Proxy Manager@Scre CodeFileEditSelectionView→Nginx Proxy Manager@Screenpipe - ArchiveSQLite Web: archive.dbSQLite Web: db.sqlitescreenpipe/.claude/skills at main - screenpipe/screenpDXP4800PLUS-B5F8AFFiNE - All In One KnowledgeOSAll docs • AFFiNEPayments LoggerM Your old PC can run Windows 11 in a VM, but not on baLocation LoggerFinance HubFinance HubSelect: transactions - db - AdminerClaude Code | Claude Platform* April 2026 spending by category - Claudelakylak/finance-hub - finance-hub - Gitea: Git with a c• Applications - Admin - authentik+ New TabGoRunTerminalWindow Helpnas.lakylak.xyz/desktop/?os=ugospro#/|FilesControl PanelPRIIStorageApp Center/logsLogsSupportQ Search|Connection & AccessUser ManagementFile ServiceW DeviceConnectionDomain/LDAP• TerminalGeneral|Hardware & PowerTime & Language- NetworkSecurityE Indexing ServiceService• About‹ $0lihlE: Control Panel100% C8Sat 9 May 21:00:47CU AM I384ВQ?TelnetSSHEnablePort 23|Advanced settings• EnablePort22Shut down automatically3h later2026-05-09 21:18 will automatically shut downAdvanced settingsFunction descriptionyaswvord fir tie logi accoum ange nabie aute ok eo enhanice sysfeum secuitis recomended to sel a strongApply...
|
NULL
|
-8070779024925180309
|
NULL
|
visual_change
|
ocr
|
NULL
|
CodeFileEditSelectionView→Nginx Proxy Manager@Scre CodeFileEditSelectionView→Nginx Proxy Manager@Screenpipe - ArchiveSQLite Web: archive.dbSQLite Web: db.sqlitescreenpipe/.claude/skills at main - screenpipe/screenpDXP4800PLUS-B5F8AFFiNE - All In One KnowledgeOSAll docs • AFFiNEPayments LoggerM Your old PC can run Windows 11 in a VM, but not on baLocation LoggerFinance HubFinance HubSelect: transactions - db - AdminerClaude Code | Claude Platform* April 2026 spending by category - Claudelakylak/finance-hub - finance-hub - Gitea: Git with a c• Applications - Admin - authentik+ New TabGoRunTerminalWindow Helpnas.lakylak.xyz/desktop/?os=ugospro#/|FilesControl PanelPRIIStorageApp Center/logsLogsSupportQ Search|Connection & AccessUser ManagementFile ServiceW DeviceConnectionDomain/LDAP• TerminalGeneral|Hardware & PowerTime & Language- NetworkSecurityE Indexing ServiceService• About‹ $0lihlE: Control Panel100% C8Sat 9 May 21:00:47CU AM I384ВQ?TelnetSSHEnablePort 23|Advanced settings• EnablePort22Shut down automatically3h later2026-05-09 21:18 will automatically shut downAdvanced settingsFunction descriptionyaswvord fir tie logi accoum ange nabie aute ok eo enhanice sysfeum secuitis recomended to sel a strongApply...
|
14480
|
NULL
|
NULL
|
NULL
|
|
25309
|
1062
|
8
|
2026-05-12T11:07:57.689098+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-12/1778 /Users/lukas/.screenpipe/data/data/2026-05-12/1778584077689_m1.jpg...
|
Firefox
|
Pipelines - jiminny/app — Work
|
True
|
app.circleci.com/pipelines/github/jiminny/app
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Unnamed Group
TypeError: League\Flysystem\Filesyst Unnamed Group
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
CloudWatch | us-east-2
CloudWatch | us-east-2
Unnamed Group
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Pull requests · jiminny/app
Pull requests · jiminny/app
[JY-20773] User Pilot not receiving events on report generated - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
JY-20773 fix user pilot tracking for automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking for automated report generated by LakyLak · Pull Request #12024 · jiminny/app
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
Data Explorer
Data Explorer
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
Jiminny
Jiminny
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
[SRD-6793] Les Mills activity types not pulling in - Jira
[SRD-6793] Les Mills activity types not pulling in - Jira
Platform Team - Backlog - Jira
Platform Team - Backlog - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
JY-20773 fix user pilot tracking for automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking for automated report generated by LakyLak · Pull Request #12024 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Close tab
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Go to home page
Auto theme
Open notifications
Open support menu
Open user menu
org avatar Current organization: jiminny
Home
Home
Pipelines
Pipelines
Projects
Projects
Deploys
Deploys
Insights
Insights
Runners
Runners
Org
Org
Plan
Plan
Chunk sidecars
Chunk sidecars
PREVIEW
Chunk
Chunk
Dashboard All Pipelines
All Pipelines
Project Outline app
app
app
app
Overview
Overview
Settings
Settings
Deploys
Deploys
Lightning Manage triggers
Manage triggers
Trigger Pipeline
Pipelines All pipelines my-pipelines-filter
All pipelines
app Project Filter. Selected "app"
app
All branches Branch Filter. Selected "All branches"
All branches
Start Time Cutoff date Arrow Drop Down
Cutoff date
All statuses Arrow Drop Down
All
statuses
Filter
Pipeline
Status
Workflow
Checkout source
Trigger event
Start/Duration
Actions
app
58250
58250
RUNNING workflow build_accept_deploy. Collapse the workflow jobs list.
Status Running Running
Running
10m 33s
remain
Info Outline
build_accept_deploy
build_accept_deploy
JY-20606-desktop-app-recall
JY-20606-desktop-app-recall
Open commit on version control site
13a63f7
JY-20606: add provider detection
Push
Commit pushed
Copy timestamp to clipboard
13m ago
Copy timestamp duration to clipboard
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
885223
1m 16s
1m 16s
SUCCESS job build-frontend
build-frontend
885224
1m 17s
1m 17s
SUCCESS job test-frontend
test-frontend
885225
1m 53s
1m 53s
SUCCESS job build-backend
build-backend
885226
55s
55s
SUCCESS job phpstan
phpstan
885239
1m 25s
1m 25s
SUCCESS job prepare_deploy_revision_subenv
prepare_deploy_revision_subenv
885230
1m 2s
1m 2s
SUCCESS job build_docker_backend_code_subenv
build_docker_backend_code_subenv
885231
1m 54s
1m 54s
SUCCESS job build_docker_worker_code_subenv
build_docker_worker_code_subenv
885232
1m 56s
1m 56s
SUCCESS job build_docker_worker_video_code_subenv
build_docker_worker_video_code_subenv
885233
1m 50s
1m 50s
SUCCESS job db_migrations_subenv
db_migrations_subenv
885235
19s
19s
SUCCESS job deploy_docker_backend_code_subenv
deploy_docker_backend_code_subenv
885237
5m 15s
5m 15s
SUCCESS job deploy_docker_worker_code_subenv
deploy_docker_worker_code_subenv
885238
2m 5s
2m 5s
SUCCESS job deploy_docker_worker_video_code_subenv
deploy_docker_worker_video_code_subenv
885236
30s
30s
SUCCESS job deploy_frontend_assets_to_s3_subenv
deploy_frontend_assets_to_s3_subenv
885234
57s
57s
SUCCESS job setup
setup
885228
1m 5s
1m 5s
SUCCESS job test
test
885229
9m 5s
9m 5s
SUCCESS job test-backend-lint
test-backend-lint
885227
4m 17s
4m 17s
RUNNING job sonar_cloud
sonar_cloud
885240
1m 42s
1m 42s
SUCCESS workflow setup-workflow. Collapse the workflow jobs list.
Status Passed Success
Success
setup-workflow
setup-workflow
SETUP
JY-20606-desktop-app-recall
JY-20606-desktop-app-recall
Open commit on version control site
13a63f7
JY-20606: add provider detection
Push
Commit pushed
Copy timestamp to clipboard
14m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Fix workflow
More Actions
Jobs
SUCCESS job setup
setup
885222
47s
47s
app
58249
58249
RUNNING workflow build_accept_deploy. Collapse the workflow jobs list.
Status Running Running
Running
20m 39s
remain
Info Outline
build_accept_deploy
build_accept_deploy
JY-20773-fix-automated-reports-user-pilot-tracking
JY-20773-fix-automated-reports-user-pilot-tracking
Open commit on version control site
62861fa
Merge branch 'master' into JY-20773-fix-automated-reports-user-pilot-tracking
Rerun
from failed
Copy timestamp to clipboard
2m ago
Copy timestamp duration to clipboard
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
885213
1m 38s
1m 38s
SUCCESS job build-frontend
build-frontend
885216
1m 29s
1m 29s
SUCCESS job test-frontend
test-frontend
885218
1m 43s
1m 43s
SUCCESS job build-backend
build-backend
885214
1m 12s
1m 12s
SUCCESS job phpstan
phpstan
885219
2m 18s
2m 18s
SUCCESS job setup
setup
885217
59s
59s
RUNNING job test
test
885241
4m 29s
4m 29s
SUCCESS job test-backend-lint
test-backend-lint
885215
4m 20s
4m 20s
sonar_cloud
885242
FAILED workflow build_accept_deploy. Collapse the workflow jobs list.
Status Failed Failed
Failed
build_accept_deploy
build_accept_deploy
JY-20773-fix-automated-reports-user-pilot-tracking
JY-20773-fix-automated-reports-user-pilot-tracking
Open commit on version control site
62861fa
Merge branch 'master' into JY-20773-fix-automated-reports-user-pilot-tracking
Push
Commit pushed
Copy timestamp to clipboard
18m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
885213
1m 38s
1m 38s
SUCCESS job build-frontend
build-frontend
885216
1m 29s
1m 29s
SUCCESS job test-frontend
test-frontend
885218
1m 43s
1m 43s
SUCCESS job build-backend
build-backend
885214
1m 12s
1m 12s
SUCCESS job phpstan
phpstan
885219
2m 18s
2m 18s
SUCCESS job setup
setup
885217
59s
59s
FAILED job test
test
885220
8m 57s
8m 57s
Fix job
SUCCESS job test-backend-lint
test-backend-lint
885215
4m 20s
4m 20s
sonar_cloud
885221
SUCCESS workflow setup-workflow. Collapse the workflow jobs list.
Status Passed Success
Success
setup-workflow
setup-workflow
SETUP
JY-20773-fix-automated-reports-user-pilot-tracking
JY-20773-fix-automated-reports-user-pilot-tracking
Open commit on version control site
62861fa
Merge branch 'master' into JY-20773-fix-automated-reports-user-pilot-tracking
Push
Commit pushed
Copy timestamp to clipboard
19m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Fix workflow
More Actions
Jobs
SUCCESS job setup
setup
885212
32s
32s
app
58248
58248
SUCCESS workflow build_accept_deploy. Collapse the workflow jobs list.
Status Passed Success
Success
build_accept_deploy
build_accept_deploy
mcp-tools-schemas
mcp-tools-schemas
Open commit on version control site
c745be1
Enhance tools-list.json by updating property types and descriptions for improved functionality and clarity. Changes include converting several fields to accept arrays for multiple entries, refining search capabilities, and clarifying usage instructions for better API documentation.
Push
Commit pushed
Copy timestamp to clipboard
35m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Fix workflow...
|
[{"role":"AXButton","text" [{"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":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — 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":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | us-east-2","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | us-east-2","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":"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":"AXRadioButton","text":"[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - 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":"[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · 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-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · 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":"Pull requests · 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":"Pull requests · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20773] User Pilot not receiving events on report generated - 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":"[JY-20773] User Pilot not receiving events on report generated - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20773 fix user pilot tracking for 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 for 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":"[JY-20776] Automated report - sentry - 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":"[JY-20776] Automated report - sentry - Jira","depth":5,"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":"AXRadioButton","text":"JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · 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-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Data Explorer","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Data Explorer","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20776] Automated report - sentry - 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":"[JY-20776] Automated report - sentry - Jira","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":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · 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-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6793] Les Mills activity types not pulling in - 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":"[SRD-6793] Les Mills activity types not pulling in - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Team - Backlog - 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 Team - Backlog - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20773] User Pilot not receiving events on report generated - 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":"[JY-20773] User Pilot not receiving events on report generated - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20773 fix user pilot tracking for 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 for 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":"Pipelines - jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Pipelines - jiminny/app","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":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · 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-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · 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,"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,"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,"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,"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,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Go to home page","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Auto theme","depth":9,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open notifications","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":"Open support menu","depth":9,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Open user menu","depth":9,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"org avatar Current organization: jiminny","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":"Home","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Home","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pipelines","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Projects","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Projects","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Deploys","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Deploys","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Runners","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Runners","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Org","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Org","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Plan","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Plan","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chunk sidecars","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Chunk sidecars","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"PREVIEW","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chunk","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Chunk","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Dashboard All Pipelines","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All Pipelines","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Project Outline app","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"app","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Overview","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Overview","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Deploys","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Deploys","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Lightning Manage triggers","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Manage triggers","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Trigger Pipeline","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":"AXButton","text":"Pipelines All pipelines my-pipelines-filter","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":"All pipelines","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"app Project Filter. Selected \"app\"","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":"app","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"All branches Branch Filter. Selected \"All branches\"","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":"All branches","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Start Time Cutoff date Arrow Drop Down","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":"Cutoff date","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"All statuses Arrow Drop Down","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","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"statuses","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Filter","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":"Pipeline","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Status","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Workflow","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Checkout source","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Trigger event","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Start/Duration","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Actions","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"58250","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"58250","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"RUNNING workflow build_accept_deploy. Collapse the workflow jobs list.","depth":13,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Running Running","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Running","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"10m 33s","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"remain","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Info Outline","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"build_accept_deploy","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_accept_deploy","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20606-desktop-app-recall","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20606-desktop-app-recall","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"13a63f7","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20606: add provider detection","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"13m ago","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"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":"Jobs","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job checkout-code","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"checkout-code","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885223","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 16s","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 16s","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build-frontend","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-frontend","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885224","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 17s","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 17s","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job test-frontend","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-frontend","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885225","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 53s","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 53s","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build-backend","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-backend","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885226","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"55s","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"55s","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job phpstan","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"phpstan","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885239","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 25s","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 25s","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job prepare_deploy_revision_subenv","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"prepare_deploy_revision_subenv","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885230","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 2s","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 2s","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build_docker_backend_code_subenv","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_docker_backend_code_subenv","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885231","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 54s","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 54s","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build_docker_worker_code_subenv","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_docker_worker_code_subenv","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885232","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 56s","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 56s","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build_docker_worker_video_code_subenv","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_docker_worker_video_code_subenv","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885233","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 50s","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 50s","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job db_migrations_subenv","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"db_migrations_subenv","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885235","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"19s","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"19s","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job deploy_docker_backend_code_subenv","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"deploy_docker_backend_code_subenv","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885237","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"5m 15s","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5m 15s","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job deploy_docker_worker_code_subenv","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"deploy_docker_worker_code_subenv","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885238","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2m 5s","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2m 5s","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job deploy_docker_worker_video_code_subenv","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"deploy_docker_worker_video_code_subenv","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885236","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"30s","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"30s","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job deploy_frontend_assets_to_s3_subenv","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"deploy_frontend_assets_to_s3_subenv","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885234","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"57s","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"57s","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job setup","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885228","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 5s","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 5s","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job test","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885229","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"9m 5s","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"9m 5s","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job test-backend-lint","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-backend-lint","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885227","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"4m 17s","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4m 17s","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"RUNNING job sonar_cloud","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"sonar_cloud","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885240","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 42s","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 42s","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"SUCCESS workflow setup-workflow. Collapse the workflow jobs list.","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Passed Success","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Success","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"setup-workflow","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup-workflow","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SETUP","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20606-desktop-app-recall","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20606-desktop-app-recall","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"13a63f7","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20606: add provider detection","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"14m ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job setup","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885222","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"47s","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"47s","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"58249","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"58249","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"RUNNING workflow build_accept_deploy. Collapse the workflow jobs list.","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Running Running","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Running","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"20m 39s","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"remain","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Info Outline","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"build_accept_deploy","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_accept_deploy","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20773-fix-automated-reports-user-pilot-tracking","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20773-fix-automated-reports-user-pilot-tracking","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"62861fa","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merge branch 'master' into JY-20773-fix-automated-reports-user-pilot-tracking","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Rerun","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from failed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2m ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job checkout-code","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"checkout-code","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885213","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 38s","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 38s","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build-frontend","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-frontend","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885216","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 29s","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 29s","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job test-frontend","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-frontend","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885218","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 43s","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 43s","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build-backend","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-backend","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885214","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 12s","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 12s","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job phpstan","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"phpstan","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885219","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2m 18s","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2m 18s","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job setup","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885217","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"59s","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"59s","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"RUNNING job test","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885241","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"4m 29s","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4m 29s","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job test-backend-lint","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-backend-lint","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885215","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"4m 20s","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4m 20s","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"sonar_cloud","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885242","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"FAILED workflow build_accept_deploy. Collapse the workflow jobs list.","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Failed Failed","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Failed","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"build_accept_deploy","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_accept_deploy","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20773-fix-automated-reports-user-pilot-tracking","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20773-fix-automated-reports-user-pilot-tracking","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"62861fa","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merge branch 'master' into JY-20773-fix-automated-reports-user-pilot-tracking","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"18m ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job checkout-code","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"checkout-code","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885213","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 38s","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 38s","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build-frontend","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-frontend","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885216","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 29s","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 29s","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job test-frontend","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-frontend","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885218","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 43s","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 43s","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build-backend","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-backend","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885214","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 12s","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 12s","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job phpstan","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"phpstan","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885219","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2m 18s","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2m 18s","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job setup","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885217","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"59s","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"59s","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"FAILED job test","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885220","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"8m 57s","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"8m 57s","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Fix job","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"SUCCESS job test-backend-lint","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-backend-lint","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885215","depth":16,"bounds":{"left":0.0,"top":0.0,"width":0.034027778,"height":0.019444445},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"4m 20s","depth":14,"bounds":{"left":0.27395833,"top":0.0,"width":0.03576389,"height":0.026666667},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4m 20s","depth":15,"bounds":{"left":0.27395833,"top":0.0,"width":0.03576389,"height":0.019444445},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"sonar_cloud","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885221","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"SUCCESS workflow setup-workflow. Collapse the workflow jobs list.","depth":13,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Passed Success","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Success","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"setup-workflow","depth":12,"bounds":{"left":0.0,"top":0.007222222,"width":0.06666667,"height":0.04388889},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup-workflow","depth":13,"bounds":{"left":0.0,"top":0.008333334,"width":0.042708334,"height":0.041666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SETUP","depth":12,"bounds":{"left":0.0,"top":0.061666667,"width":0.023263888,"height":0.013888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20773-fix-automated-reports-user-pilot-tracking","depth":13,"bounds":{"left":0.0,"top":0.0027777778,"width":0.153125,"height":0.04388889},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20773-fix-automated-reports-user-pilot-tracking","depth":14,"bounds":{"left":0.0,"top":0.003888889,"width":0.12569444,"height":0.041666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"bounds":{"left":0.0,"top":0.05111111,"width":0.153125,"height":0.046666667},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"62861fa","depth":16,"bounds":{"left":0.0,"top":0.05277778,"width":0.03784722,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merge branch 'master' into JY-20773-fix-automated-reports-user-pilot-tracking","depth":16,"bounds":{"left":0.0,"top":0.05277778,"width":0.12465278,"height":0.08944444},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"bounds":{"left":0.175,"top":0.006666667,"width":0.023263888,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"bounds":{"left":0.175,"top":0.024444444,"width":0.072222225,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"bounds":{"left":0.27638888,"top":0.0027777778,"width":0.055555556,"height":0.044444446},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"19m ago","depth":15,"bounds":{"left":0.29479167,"top":0.006666667,"width":0.01875,"height":0.03722222},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"bounds":{"left":0.29027778,"top":0.051666666,"width":0.041666668,"height":0.044444446},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"bounds":{"left":0.36527777,"top":0.007222222,"width":0.022222223,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"bounds":{"left":0.3875,"top":0.007222222,"width":0.022222223,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"bounds":{"left":0.4097222,"top":0.007222222,"width":0.022222223,"height":0.035555556},"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":"Jobs","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job setup","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885212","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"32s","depth":14,"bounds":{"left":0.29201388,"top":0.12888889,"width":0.017708333,"height":0.026666667},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"32s","depth":15,"bounds":{"left":0.29201388,"top":0.13222222,"width":0.017708333,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"58248","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"58248","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"SUCCESS workflow build_accept_deploy. Collapse the workflow jobs list.","depth":13,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Passed Success","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Success","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"build_accept_deploy","depth":12,"bounds":{"left":0.0,"top":0.20666666,"width":0.06666667,"height":0.043333333},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_accept_deploy","depth":13,"bounds":{"left":0.0,"top":0.20777778,"width":0.06388889,"height":0.04111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"mcp-tools-schemas","depth":13,"bounds":{"left":0.0,"top":0.20222223,"width":0.09375,"height":0.021666666},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"mcp-tools-schemas","depth":14,"bounds":{"left":0.0,"top":0.20333333,"width":0.09375,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"bounds":{"left":0.0,"top":0.22833334,"width":0.153125,"height":0.046666667},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"c745be1","depth":16,"bounds":{"left":0.0,"top":0.23,"width":0.03923611,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Enhance tools-list.json by updating property types and descriptions for improved functionality and clarity. Changes include converting several fields to accept arrays for multiple entries, refining search capabilities, and clarifying usage instructions for better API documentation.","depth":16,"bounds":{"left":0.0,"top":0.23,"width":0.13645834,"height":0.25277779},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"bounds":{"left":0.175,"top":0.20555556,"width":0.023263888,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"bounds":{"left":0.175,"top":0.22333333,"width":0.072222225,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"bounds":{"left":0.27638888,"top":0.20222223,"width":0.055555556,"height":0.044444446},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"35m ago","depth":15,"bounds":{"left":0.29375,"top":0.20555556,"width":0.020833334,"height":0.03722222},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"bounds":{"left":0.27638888,"top":0.25111112,"width":0.055555556,"height":0.044444446},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"bounds":{"left":0.36527777,"top":0.20666666,"width":0.022222223,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"bounds":{"left":0.3875,"top":0.20666666,"width":0.022222223,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false}]...
|
-8069750489870785359
|
-3744951293718924144
|
idle
|
accessibility
|
NULL
|
Unnamed Group
TypeError: League\Flysystem\Filesyst Unnamed Group
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
CloudWatch | us-east-2
CloudWatch | us-east-2
Unnamed Group
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Pull requests · jiminny/app
Pull requests · jiminny/app
[JY-20773] User Pilot not receiving events on report generated - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
JY-20773 fix user pilot tracking for automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking for automated report generated by LakyLak · Pull Request #12024 · jiminny/app
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
Data Explorer
Data Explorer
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
Jiminny
Jiminny
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
[SRD-6793] Les Mills activity types not pulling in - Jira
[SRD-6793] Les Mills activity types not pulling in - Jira
Platform Team - Backlog - Jira
Platform Team - Backlog - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
JY-20773 fix user pilot tracking for automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking for automated report generated by LakyLak · Pull Request #12024 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Close tab
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Go to home page
Auto theme
Open notifications
Open support menu
Open user menu
org avatar Current organization: jiminny
Home
Home
Pipelines
Pipelines
Projects
Projects
Deploys
Deploys
Insights
Insights
Runners
Runners
Org
Org
Plan
Plan
Chunk sidecars
Chunk sidecars
PREVIEW
Chunk
Chunk
Dashboard All Pipelines
All Pipelines
Project Outline app
app
app
app
Overview
Overview
Settings
Settings
Deploys
Deploys
Lightning Manage triggers
Manage triggers
Trigger Pipeline
Pipelines All pipelines my-pipelines-filter
All pipelines
app Project Filter. Selected "app"
app
All branches Branch Filter. Selected "All branches"
All branches
Start Time Cutoff date Arrow Drop Down
Cutoff date
All statuses Arrow Drop Down
All
statuses
Filter
Pipeline
Status
Workflow
Checkout source
Trigger event
Start/Duration
Actions
app
58250
58250
RUNNING workflow build_accept_deploy. Collapse the workflow jobs list.
Status Running Running
Running
10m 33s
remain
Info Outline
build_accept_deploy
build_accept_deploy
JY-20606-desktop-app-recall
JY-20606-desktop-app-recall
Open commit on version control site
13a63f7
JY-20606: add provider detection
Push
Commit pushed
Copy timestamp to clipboard
13m ago
Copy timestamp duration to clipboard
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
885223
1m 16s
1m 16s
SUCCESS job build-frontend
build-frontend
885224
1m 17s
1m 17s
SUCCESS job test-frontend
test-frontend
885225
1m 53s
1m 53s
SUCCESS job build-backend
build-backend
885226
55s
55s
SUCCESS job phpstan
phpstan
885239
1m 25s
1m 25s
SUCCESS job prepare_deploy_revision_subenv
prepare_deploy_revision_subenv
885230
1m 2s
1m 2s
SUCCESS job build_docker_backend_code_subenv
build_docker_backend_code_subenv
885231
1m 54s
1m 54s
SUCCESS job build_docker_worker_code_subenv
build_docker_worker_code_subenv
885232
1m 56s
1m 56s
SUCCESS job build_docker_worker_video_code_subenv
build_docker_worker_video_code_subenv
885233
1m 50s
1m 50s
SUCCESS job db_migrations_subenv
db_migrations_subenv
885235
19s
19s
SUCCESS job deploy_docker_backend_code_subenv
deploy_docker_backend_code_subenv
885237
5m 15s
5m 15s
SUCCESS job deploy_docker_worker_code_subenv
deploy_docker_worker_code_subenv
885238
2m 5s
2m 5s
SUCCESS job deploy_docker_worker_video_code_subenv
deploy_docker_worker_video_code_subenv
885236
30s
30s
SUCCESS job deploy_frontend_assets_to_s3_subenv
deploy_frontend_assets_to_s3_subenv
885234
57s
57s
SUCCESS job setup
setup
885228
1m 5s
1m 5s
SUCCESS job test
test
885229
9m 5s
9m 5s
SUCCESS job test-backend-lint
test-backend-lint
885227
4m 17s
4m 17s
RUNNING job sonar_cloud
sonar_cloud
885240
1m 42s
1m 42s
SUCCESS workflow setup-workflow. Collapse the workflow jobs list.
Status Passed Success
Success
setup-workflow
setup-workflow
SETUP
JY-20606-desktop-app-recall
JY-20606-desktop-app-recall
Open commit on version control site
13a63f7
JY-20606: add provider detection
Push
Commit pushed
Copy timestamp to clipboard
14m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Fix workflow
More Actions
Jobs
SUCCESS job setup
setup
885222
47s
47s
app
58249
58249
RUNNING workflow build_accept_deploy. Collapse the workflow jobs list.
Status Running Running
Running
20m 39s
remain
Info Outline
build_accept_deploy
build_accept_deploy
JY-20773-fix-automated-reports-user-pilot-tracking
JY-20773-fix-automated-reports-user-pilot-tracking
Open commit on version control site
62861fa
Merge branch 'master' into JY-20773-fix-automated-reports-user-pilot-tracking
Rerun
from failed
Copy timestamp to clipboard
2m ago
Copy timestamp duration to clipboard
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
885213
1m 38s
1m 38s
SUCCESS job build-frontend
build-frontend
885216
1m 29s
1m 29s
SUCCESS job test-frontend
test-frontend
885218
1m 43s
1m 43s
SUCCESS job build-backend
build-backend
885214
1m 12s
1m 12s
SUCCESS job phpstan
phpstan
885219
2m 18s
2m 18s
SUCCESS job setup
setup
885217
59s
59s
RUNNING job test
test
885241
4m 29s
4m 29s
SUCCESS job test-backend-lint
test-backend-lint
885215
4m 20s
4m 20s
sonar_cloud
885242
FAILED workflow build_accept_deploy. Collapse the workflow jobs list.
Status Failed Failed
Failed
build_accept_deploy
build_accept_deploy
JY-20773-fix-automated-reports-user-pilot-tracking
JY-20773-fix-automated-reports-user-pilot-tracking
Open commit on version control site
62861fa
Merge branch 'master' into JY-20773-fix-automated-reports-user-pilot-tracking
Push
Commit pushed
Copy timestamp to clipboard
18m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
885213
1m 38s
1m 38s
SUCCESS job build-frontend
build-frontend
885216
1m 29s
1m 29s
SUCCESS job test-frontend
test-frontend
885218
1m 43s
1m 43s
SUCCESS job build-backend
build-backend
885214
1m 12s
1m 12s
SUCCESS job phpstan
phpstan
885219
2m 18s
2m 18s
SUCCESS job setup
setup
885217
59s
59s
FAILED job test
test
885220
8m 57s
8m 57s
Fix job
SUCCESS job test-backend-lint
test-backend-lint
885215
4m 20s
4m 20s
sonar_cloud
885221
SUCCESS workflow setup-workflow. Collapse the workflow jobs list.
Status Passed Success
Success
setup-workflow
setup-workflow
SETUP
JY-20773-fix-automated-reports-user-pilot-tracking
JY-20773-fix-automated-reports-user-pilot-tracking
Open commit on version control site
62861fa
Merge branch 'master' into JY-20773-fix-automated-reports-user-pilot-tracking
Push
Commit pushed
Copy timestamp to clipboard
19m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Fix workflow
More Actions
Jobs
SUCCESS job setup
setup
885212
32s
32s
app
58248
58248
SUCCESS workflow build_accept_deploy. Collapse the workflow jobs list.
Status Passed Success
Success
build_accept_deploy
build_accept_deploy
mcp-tools-schemas
mcp-tools-schemas
Open commit on version control site
c745be1
Enhance tools-list.json by updating property types and descriptions for improved functionality and clarity. Changes include converting several fields to accept arrays for multiple entries, refining search capabilities, and clarifying usage instructions for better API documentation.
Push
Commit pushed
Copy timestamp to clipboard
35m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Fix workflow...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
2125
|
98
|
45
|
2026-05-07T11:02:44.235269+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778151764235_m2.jpg...
|
iTerm2
|
NULL
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
rostmancaltvlewWindowmelprTavsco.s°9 masterProlede rostmancaltvlewWindowmelprTavsco.s°9 masterProledey© RingCentral/Client.phpA EU (EU]v &[EMAIL]© RateLimitException.php© RateLimitAwareWrapper.php& console uiminny clocainosA DI [jiminny@localhost]A HS_local [jiminny@localhosA SF ([jiminny@localhost]A zoho_dev (jiminny@localhoV A PRODMiddleware/RateLimited.pnpuHtp/RateLimited.phpC) ProviderRateLimiter.pho Xclass ProviderRateLimiterpublic function canMakeRequest(RateLimited Sprovider): bool& console PrODI& console 1 PRODLDI PROD I> AOA/** @vac RateLimitinterface SrateLimit */foreach (Sprovider->getRateLimits) as SrateLimit)‹$key = SrateLimit->getKeyO:L@AI#QAI PRODLSTAGINGif (Sthis->rateLimiter->tooManyAttempts(Skey, SrateLimit->getQuotaO)) {neturn false.& console STAGING& console STAGiNgduranus STAGINGI> Fxtansinnsservicesv D DatabaseV AEUconsolev &iiminny@localhostA HS local 1s 212 msA SFV A PRODconsole 1s 381 msASTAGING¿ console 1s 901 ms÷ Docker© SyncToUserPilot.phpv 520522524525526527= custom.log= laravel.log4 SF jiminny@localhoA console [STAGING] XTx: Auto vCONCATCU.10. CASE WHEN U.10 = 1.0U.eman..sa.*t.owner 1d FROM social accounts s.JOIN users u on u.id = sa.sociable_icVOIN teams t 1..n<->1on t.id = u.te:WHERE U.team_id = 1052 and sa.provideselect * from teams where id = 1;select * from groups g JOIN playbooksselect * from groups where id = 565;select * from playbooks where team_idselect * from playbooks where id = 17select * from plavbook cateaonies wheselect * from users where team_id = 1select * from users where id = 7160:h Outoutii Result 3W 1rowvWuser_idW emailDidI sociable idM provider user idM orovider user tokenl provider_refresh_tokenexpiresI refresh_ token_ expiresI providenM stateW auth_scopeI retry_afterI• created atI updated atMorovider user token encrvotedlMorovider refresh token encrvntedm encnvntion kev (Hey)I sociable type(* owner id23552 (owner)[EMAIL] 7OLNOMI 8K0EWPAOWACAKUAhI.IBB4BAOEDBX1DYWOTMSX-BU006wCMh0rvv03z0W700hF0GvochLCo/mLiov0l.N0M1 8k05na1-1522-0818-4440-868b-141165c3ed07177/390304hubspotful-refresh¿nulls2025-11-17 21:21:132026-03-24 06:06:20evJodiT6T#Z2UXN1KzdTbEFLL3czMXVia01+SFE9PSIsInZhbHV1ToiTEFCYXZ5d3dHcGFVMnoNak03NXRvaHM0Z1VaWnF10WT2S010cD|ev.JodiT6TlhGeFRt0Td.JZvt5ZUV≥MzJERmE00UE9PSIsInZhbHV1TioiMTFHcnq3TihMT2x@c2RTVHJJMT16a1RidnoBYLVYTktJVVo0eT*Ax010203007861920909600600301ERCQ0EAEES5AC/5E580165CE3E302R3R627026AA7CEC7CA01AANARCCA37320C1065F20A1R84R923552"suppont Dally • In oomXx Hubspot v• SearchYour team is now on the Free plan with 1 admin. You retain editing access and other members are read-only. View team permissions to see who can edit, or upgrade to restore collaborationGET Re:•GET Get'No environmentvHTTP https:api.hubapi.com/account-info/v3/detaia SaveShareV COLLECTIONShttps://api.hubapi.com/account-info/v3/detaiAssociations V4= DocsAuthorization • Headers 8 Body Scripts SettingscookiesCMS - URL Redirects APl CollectionToken• Companies{{token})• COMPAREThe authorization header will be• Contactsautomatically generated when vou send• CRM ObiectsCRM Ownersbearer lloken authorization• CRM Pipelines• Dealsv Engagements> O OLD ENGAGEMENTSGet list meetinasPOST search modified comnaniesPOST search tasksGET read calll› POST search callsGET list callspost meetinas scheduledGET get meetingPoSt aet link tolit.skPost Greate Contact with AccociationHubspot• Iournal & wehhoooks vA> ©Auth• Pronertiec> RESEARCH• СЕАРСН> Tickets• Ulsefule> Webhooks100% L2Thu 7 May 14:02:43VAllIVariables in requestG tokenCMiYz9LaMx|7a..>All variablesSend + Get a successful responseo Send + Visualize response# Send + Write testsCAMIDONMCNTeSPECS>FLOWSGlobals Vault Tools?0O...
|
NULL
|
-8068502238361053294
|
NULL
|
visual_change
|
ocr
|
NULL
|
rostmancaltvlewWindowmelprTavsco.s°9 masterProlede rostmancaltvlewWindowmelprTavsco.s°9 masterProledey© RingCentral/Client.phpA EU (EU]v &[EMAIL]© RateLimitException.php© RateLimitAwareWrapper.php& console uiminny clocainosA DI [jiminny@localhost]A HS_local [jiminny@localhosA SF ([jiminny@localhost]A zoho_dev (jiminny@localhoV A PRODMiddleware/RateLimited.pnpuHtp/RateLimited.phpC) ProviderRateLimiter.pho Xclass ProviderRateLimiterpublic function canMakeRequest(RateLimited Sprovider): bool& console PrODI& console 1 PRODLDI PROD I> AOA/** @vac RateLimitinterface SrateLimit */foreach (Sprovider->getRateLimits) as SrateLimit)‹$key = SrateLimit->getKeyO:L@AI#QAI PRODLSTAGINGif (Sthis->rateLimiter->tooManyAttempts(Skey, SrateLimit->getQuotaO)) {neturn false.& console STAGING& console STAGiNgduranus STAGINGI> Fxtansinnsservicesv D DatabaseV AEUconsolev &iiminny@localhostA HS local 1s 212 msA SFV A PRODconsole 1s 381 msASTAGING¿ console 1s 901 ms÷ Docker© SyncToUserPilot.phpv 520522524525526527= custom.log= laravel.log4 SF jiminny@localhoA console [STAGING] XTx: Auto vCONCATCU.10. CASE WHEN U.10 = 1.0U.eman..sa.*t.owner 1d FROM social accounts s.JOIN users u on u.id = sa.sociable_icVOIN teams t 1..n<->1on t.id = u.te:WHERE U.team_id = 1052 and sa.provideselect * from teams where id = 1;select * from groups g JOIN playbooksselect * from groups where id = 565;select * from playbooks where team_idselect * from playbooks where id = 17select * from plavbook cateaonies wheselect * from users where team_id = 1select * from users where id = 7160:h Outoutii Result 3W 1rowvWuser_idW emailDidI sociable idM provider user idM orovider user tokenl provider_refresh_tokenexpiresI refresh_ token_ expiresI providenM stateW auth_scopeI retry_afterI• created atI updated atMorovider user token encrvotedlMorovider refresh token encrvntedm encnvntion kev (Hey)I sociable type(* owner id23552 (owner)[EMAIL] 7OLNOMI 8K0EWPAOWACAKUAhI.IBB4BAOEDBX1DYWOTMSX-BU006wCMh0rvv03z0W700hF0GvochLCo/mLiov0l.N0M1 8k05na1-1522-0818-4440-868b-141165c3ed07177/390304hubspotful-refresh¿nulls2025-11-17 21:21:132026-03-24 06:06:20evJodiT6T#Z2UXN1KzdTbEFLL3czMXVia01+SFE9PSIsInZhbHV1ToiTEFCYXZ5d3dHcGFVMnoNak03NXRvaHM0Z1VaWnF10WT2S010cD|ev.JodiT6TlhGeFRt0Td.JZvt5ZUV≥MzJERmE00UE9PSIsInZhbHV1TioiMTFHcnq3TihMT2x@c2RTVHJJMT16a1RidnoBYLVYTktJVVo0eT*Ax010203007861920909600600301ERCQ0EAEES5AC/5E580165CE3E302R3R627026AA7CEC7CA01AANARCCA37320C1065F20A1R84R923552"suppont Dally • In oomXx Hubspot v• SearchYour team is now on the Free plan with 1 admin. You retain editing access and other members are read-only. View team permissions to see who can edit, or upgrade to restore collaborationGET Re:•GET Get'No environmentvHTTP https:api.hubapi.com/account-info/v3/detaia SaveShareV COLLECTIONShttps://api.hubapi.com/account-info/v3/detaiAssociations V4= DocsAuthorization • Headers 8 Body Scripts SettingscookiesCMS - URL Redirects APl CollectionToken• Companies{{token})• COMPAREThe authorization header will be• Contactsautomatically generated when vou send• CRM ObiectsCRM Ownersbearer lloken authorization• CRM Pipelines• Dealsv Engagements> O OLD ENGAGEMENTSGet list meetinasPOST search modified comnaniesPOST search tasksGET read calll› POST search callsGET list callspost meetinas scheduledGET get meetingPoSt aet link tolit.skPost Greate Contact with AccociationHubspot• Iournal & wehhoooks vA> ©Auth• Pronertiec> RESEARCH• СЕАРСН> Tickets• Ulsefule> Webhooks100% L2Thu 7 May 14:02:43VAllIVariables in requestG tokenCMiYz9LaMx|7a..>All variablesSend + Get a successful responseo Send + Visualize response# Send + Write testsCAMIDONMCNTeSPECS>FLOWSGlobals Vault Tools?0O...
|
2124
|
NULL
|
NULL
|
NULL
|
|
25471
|
1070
|
11
|
2026-05-12T11:26:31.914792+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-12/1778 /Users/lukas/.screenpipe/data/data/2026-05-12/1778585191914_m1.jpg...
|
Claude
|
Claude
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Skip to content
Skip to content
Click to collapse
Skip to content
Skip to content
Click to collapse
⌘B
Drag to resize
Collapse sidebar
Search
Chat
Cowork
Code
New chat ⌘N
New chat
⌘N
Projects
Artifacts
Customize
Pinned
Bulgarian citizenship application process for EU residents
More options for Bulgarian citizenship application process for EU residents
Dawarich location tracking project
More options for Dawarich location tracking project
Recents
View all
Screenpipe data sync and retention management
More options for Screenpipe data sync and retention management
Screenpipe sync script failing after recent migrations
More options for Screenpipe sync script failing after recent migrations
Hubspot BadRequest headers debugging
More options for Hubspot BadRequest headers debugging
Monthly expense tracking
More options for Monthly expense tracking
Exporting transaction data from Notion to finance hub
More options for Exporting transaction data from Notion to finance hub
💬 How much have I spent for groc…
More options for 💬 How much have I spent for groc…
April 2026 spending by category
More options for April 2026 spending by category
Code diff review
More options for Code diff review
HubSpot rate limit implementation strategy
More options for HubSpot rate limit implementation strategy
Screenpipe retention policy code location
More options for Screenpipe retention policy code location
Viewing retention policy in screenpipe
More options for Viewing retention policy in screenpipe
Clean shot x video recording termination issue
More options for Clean shot x video recording termination issue
HubSpot rate limit handling with executeRequest
More options for HubSpot rate limit handling with executeRequest
Untitled
More options
💬 Screen pipe. Is there ability…
More options for 💬 Screen pipe. Is there ability…
SMB mount access inconsistency between Finder and iTerm
More options for SMB mount access inconsistency between Finder and iTerm
💬 What is the best switch I can…
More options for 💬 What is the best switch I can…
Permission denied on screenpipe volume
More options for Permission denied on screenpipe volume
Screenpipe sync database attachment error
More options for Screenpipe sync database attachment error
Last swimming outing with Dani
More options for Last swimming outing with Dani
Lukas Pro
Get apps and extensions
Screenpipe data sync and retention management, rename chat
Screenpipe data sync and retention management
More options for Screenpipe data sync and retention management
Close
Share chat
Claude finished the response
You said: Lets start from the beginning with the fresh mind.
You said: Lets start from the beginning with the fresh mind.
Pasted Text, pasted, 495 lines
#!/bin/bash # screenpipe_sync.sh # Syncs Screenpipe SQLite data to a NAS archive database (append-only, no deletions). # Also copies the day's video/frame data folder to the NAS. # # Schema-drift tolerant: if Screenpipe migrations add new columns to the source DB, # the NAS archive gets ALTER TABLE'
PASTED
Lets start from the beginning with the fresh mind. There is a script for screenpipe to copy data for day from mac to nas. There are two issues I want to work with. Firsts if I reinstall the mac version it starts from fresh id 1. That causes some issues. How to make sure the data are valid. I don't want some overcomplicated flow. I was thinking about making new db every 3 months. Secodn issue is that I wan to implement cleanup (retention policy) on mac original screenpipe db. I want script that will remove data that are 7 days old or older for example. ANd lastly I want to extedn the script to work with audio as well. What od you need
20:19
Retry
Edit
Copy
Claude responded: Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether…
Claude responded: Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether…
Analyzed three technical challenges and identified clarifying questions needed
Analyzed three technical challenges and identified clarifying questions needed
Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether reinstalls have already happened). Before I touch the script, a few things:
Issue 1 — ID collisions / archive rotation
Has a reinstall already happened, or is the current
archive.db
still from one continuous install? If collisions already exist I need to handle that first; if not, we have a clean slate.
Quarterly rotation works, but it doesn't actually solve reinstalls
within
a quarter. A cleaner option that I'd lean toward: add an
install_id
column (UUID generated once and stored in a tiny
_meta
table in the source DB) to every synced table, and make
(install_id, id)
the logical key. FK joins just gain one extra predicate. Reinstall → new install_id → no collisions, ever. You can still rotate the archive DB quarterly for file-size reasons, but it's no longer load-bearing.
Do you ever run cross-period queries (e.g. "every frame mentioning JY-20458 across all time")? That answers whether quarterly sharding is acceptable or whether one growing DB is better.
Issue 2 — Mac-side retention
Your launch command already has
--retention-days 7
. Is that not actually deleting anything, or do you want a separate scripted retention you can trust/observe independently?
Should retention also wipe the matching
~/.screenpipe/data/data/YYYY-MM-DD/
folders, or only DB rows? (CLI flag does both I believe; a script should match.)
Run order matters: sync writes
yesterday
, retention deletes
>7 days old
— no overlap, but I'd still chain them (sync → retention → log) in one cron entry so a failed sync blocks the delete. OK with that?
Issue 3 — Audio
Your current launch flag is
--disable-audio
, so right now there's no audio data to sync. Are you planning to enable it, or is this just to future-proof the script?
I need the audio schema. Could you run this and paste the output:
Copy to clipboard
sqlite3 ~/.screenpipe/db.sqlite ".schema" | grep -iE -A 20 "audio|transcription"
And:
ls ~/.screenpipe/data/data/$(date -v-1d +%Y-%m-%d)/ | head
so I can see what audio files look like on disk alongside the mp4 frames.
Once I have those, I'll restructure the script in one go rather than piecemeal.
Copy
Give positive feedback
Give negative feedback
Retry
You said: ok lets add install_id.
You said: ok lets add install_id.
Pasted Text, pasted, 208 lines
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ sqlite3 ~/.screenpipe/db.sqlite ".schema" | grep -iE -A 20 "audio|transcription" CREATE TABLE audio_chunks ( id INTEGER PRIMARY KEY AUTOINCREMENT, file_path TEXT NOT NULL , timestamp TIMESTAMP, sync_id TEXT, machine_id TEXT, synced_at DATETIME, ev
PASTED
ok lets add install_id. Lets add separate script deleting data again from data and it should also remove logs and data. Make it manual script for now. I will remove --disable-audio from alias and run it without. I wan to have audio as well. lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ ls ~/.screenpipe/data/data/$(date -v-1d +%Y-%m-%d)/ | head
compact_monitor_1_1778411210025.mp4
compact_monitor_1_1778413422547.mp4
compact_monitor_1_1778436664801.mp4
compact_monitor_1_1778437267451.mp4
compact_monitor_1_1778437569681.mp4
compact_monitor_1_1778437873507.mp4
compact_monitor_1_1778438175846.mp4
compact_monitor_1_1778438477299.mp4
compact_monitor_1_1778438780686.mp4
compact_monitor_1_1778439082442.mp4 Inside ~/,screenpipe/data there are data like this ... -rw-r--r-- 1 lukas staff 4628 11 May 16:48 System Audio (output)_2026-05-11_13-48-12.mp4
-rw-r--r-- 1 lukas staff 4620 11 May 16:48 System Audio (output)_2026-05-11_13-48-34.mp4
-rw-r--r-- 1 lukas staff 4620 11 May 16:49 System Audio (output)_2026-05-11_13-48-56.mp4
-rw-r--r-- 1 lukas staff 4628 11 May 16:49 System Audio (output)_2026-05-11_13-49-19.mp4
-rw-r--r-- 1 lukas staff 4620 11 May 16:50 System Audio (output)_2026-05-11_13-49-41.mp4
-rw-r--r-- 1 lukas staff 4620 11 May 16:50 System Audio (output)_2026-05-11_13-50-03.mp4
-rw-r--r-- 1 lukas staff 4628 11 May 16:50 System Audio (output)_2026-05-11_13-50-26.mp4
-rw-r--r-- 1 lukas staff 4628 11 May 16:51 System Audio (output)_2026-05-11_13-50-48.mp4
-rw-r--r-- 1 lukas staff 4620 11 May 16:51 System Audio (output)_2026-05-11_13-51-10.mp4
-rw-r--r-- 1 lukas staff 4620 11 May 16:51 System Audio (output)_2026-05-11_13-51-33.mp4
-rw-r--r-- 1 lukas staff 4620 11 May 16:52 System Audio (output)_2026-05-11_13-51-55.mp4
drwxr-xr-x 9 lukas staff 288 11 May 07:54 data
drwxr-xr-x 2 lukas staff 64 11 May 15:48 pending-transcriptions
-rw-r--r-- 1 lukas staff 29419 10 May 14:11 soundcore AeroClip (input)_2026-05-10_11-10-32.mp4
-rw-r--r-- 1 lukas staff 56479 10 May 14:11 soundcore AeroClip (input)_2026-05-10_11-11-05.mp4
-rw-r--r--@ 1 lukas staff 181831 10 May 14:12 soundcore AeroClip (input)_2026-05-10_11-11-35.mp4
-rw-r--r-- 1 lukas staff 149782 10 May 14:43 soundcore AeroClip (input)_2026-05-10_11-42-53.mp4
-rw-r--r-- 1 lukas staff 91059 10 May 14:43 soundcore AeroClip (input)_2026-05-10_11-43-25.mp4
-rw-r--r-- 1 lukas staff 30604 10 May 14:44 soundcore AeroClip (input)_2026-05-10_11-44-25.mp4
-rw-r--r-- 1 lukas staff 93813 10 May 14:45 soundcore AeroClip (input)_2026-05-10_11-44-55.mp4
-rw-r--r-- 1 lukas staff 40444 10 May 21:11 soundcore AeroClip (input)_2026-05-10_18-11-18.mp4
-rw-r--r-- 1 lukas staff 193020 10 May 21:12 soundcore AeroClip (input)_2026-05-10_18-11-48.mp4...
Show more
20:34
Retry
Edit
Copy
Claude responded: Good, that clarifies the audio layout — audio files live flat in ~/.
Claude responded: Good, that clarifies the audio layout — audio files live flat in ~/.
Architected multi-install sync with audio support and retention
Architected multi-install sync with audio support and retention
Good, that clarifies the audio layout — audio files live flat in
~/.screenpipe/data/
with the date in the filename (not in date subdirs like frames), and the schema gives us
audio_chunks
+
audio_transcriptions
+
speakers
+
speaker_embeddings
+
audio_tags
plus the FTS table on transcriptions.
Plan I'll implement:
install_id
: stored as a UUID in
~/.screenpipe/.sync_install_id
— disappears when the directory is wiped (which is what you want on reinstall). Every synced NAS table gets an
install_id TEXT
column and a
UNIQUE(install_id, id)
index. The script auto-migrates the existing NAS archive by adding the column and tagging legacy rows with
legacy-YYYYMMDD
so historical data is still queryable but doesn't conflict with future installs.
Audio sync
: adds
audio_chunks
,
audio_transcriptions
,
speakers
,
speaker_embeddings
,
audio_tags
to the sync pipeline, plus the
audio_transcriptions_fts
index. Audio files go to
$NAS_DATA/<date>/audio/
(sibling to the frames in the same date dir, keeps daily archives self-contained).
Retention
is a separate manual script — dry-run by default,
--apply
to delete. Hits DB rows, frame directories, audio mp4s, and screenpipe logs. Optional
--vacuum
with a warning (screenpipe must be stopped to avoid blocking writes for minutes).
One caveat I'm punting on: the FTS tables use source
id
as
rowid
, so after a reinstall they'd get id-collisions on insert and
INSERT OR IGNORE
would silently skip. Within a single install this is fine; after reinstall you'd fall back to
LIKE
queries on the base tables (still filterable by
install_id
). I noted this in the script. Fixing it properly needs a synthetic rowid scheme which we can do later if you actually hit it.
Let me write both:
Updated screenpipe_sync.sh with install_id support and audio sync
Updated screenpipe_sync.sh with install_id support and audio sync
Updated screenpipe_sync.sh with install_id support and audio sync
Updated screenpipe_sync.sh with install_id support and audio sync
screenpipe_sync.sh
Done
Copy
Give positive feedback
Give negative feedback
Retry
You said: I don't like that.
You said: I don't like that.
I don't like that. It should be solid without id collisions. Wouldn't it be to late if I should fix it later?
20:50
Retry
Edit
Copy
I don't like that. It should be solid without id collisions. Wouldn't it be to late if I should fix it later?
I don't like that. It should be solid without id collisions. Wouldn't it be to late if I should fix it later?
Add files, connectors, and more
Model: Opus 4.7 Adaptive
Opus 4.7
Adaptive
Send message
Claude is AI and can make mistakes. Please double-check responses.
Claude is AI and can make mistakes. Please double-check responses.
Screenpipe sync · SH
Screenpipe sync
·
SH
Copy
Close
1
#!/bin/bash
2
# screenpipe_sync.sh
3
# Syncs Screenpipe SQLite data (vision + audio) to a NAS archive database.
4
# Append-only, no deletions.
5
#
6
# Key design points
7
# -----------------
8
# 1. Multi-install safe via install_id.
9
# Source IDs reset to 1 on every screenpipe reinstall. To avoid collisions
10
# in the NAS archive, every synced table gets an extra `install_id` column,
11
# and the logical primary key becomes (install_id, id) enforced by a
12
# unique index. The install_id is a UUID stored in
13
# ~/.screenpipe/.sync_install_id — wiping ~/.screenpipe/ (which is what
14
# happens on reinstall) discards it, so the next run generates a new one.
15
#
16
# 2. Schema-drift tolerant. If screenpipe migrations add new columns to the
17
# source DB, the NAS gets ALTER TABLE'd to match. Inserts use explicit
18
# column lists so positional mismatches can't occur.
19
#
20
# 3. FTS caveat. FTS tables in the NAS use source `id` as rowid. After a
21
# reinstall, INSERT OR IGNORE will silently skip rows whose id collides
22
# with a previous install's id, so FTS only reliably indexes the most
23
# recent install. Falls back to LIKE queries on the base tables for
24
# multi-install searches (which can filter by install_id).
25
#
26
# Usage
27
# -----
28
# ./screenpipe_sync.sh # syncs yesterday
29
# ./screenpipe_sync.sh 2026-04-15 # syncs a specific date
30
# ./screenpipe_sync.sh today # syncs today so far
31
# ./screenpipe_sync.sh --reset-install-id # rotate install_id and exit
32
# ./screenpipe_sync.sh --show-install-id # print install_id and exit
33
34
set
-euo
pipefail
35
36
# ─── CONFIG ───────────────────────────────────────────────────────────────────
37...
|
[{"role":"AXLink","text":& [{"role":"AXLink","text":"Skip to content","depth":14,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Skip to content","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Click to collapse","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"⌘B","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drag to resize","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Collapse sidebar","depth":15,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search","depth":15,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Chat","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cowork","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New chat ⌘N","depth":15,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"New chat","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"⌘N","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Projects","depth":15,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Artifacts","depth":15,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Customize","depth":15,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Pinned","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"Bulgarian citizenship application process for EU residents","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Bulgarian citizenship application process for EU residents","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Dawarich location tracking project","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Dawarich location tracking project","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Recents","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"View all","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Screenpipe data sync and retention management","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Screenpipe data sync and retention management","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Screenpipe sync script failing after recent migrations","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Screenpipe sync script failing after recent migrations","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hubspot BadRequest headers debugging","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Hubspot BadRequest headers debugging","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Monthly expense tracking","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Monthly expense tracking","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Exporting transaction data from Notion to finance hub","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Exporting transaction data from Notion to finance hub","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"💬 How much have I spent for groc…","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for 💬 How much have I spent for groc…","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"April 2026 spending by category","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for April 2026 spending by category","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code diff review","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Code diff review","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HubSpot rate limit implementation strategy","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for HubSpot rate limit implementation strategy","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Screenpipe retention policy code location","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Screenpipe retention policy code location","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Viewing retention policy in screenpipe","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Viewing retention policy in screenpipe","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Clean shot x video recording termination issue","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Clean shot x video recording termination issue","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HubSpot rate limit handling with executeRequest","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for HubSpot rate limit handling with executeRequest","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Untitled","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"💬 Screen pipe. Is there ability…","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for 💬 Screen pipe. Is there ability…","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"SMB mount access inconsistency between Finder and iTerm","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for SMB mount access inconsistency between Finder and iTerm","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"💬 What is the best switch I can…","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for 💬 What is the best switch I can…","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Permission denied on screenpipe volume","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Permission denied on screenpipe volume","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Screenpipe sync database attachment error","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Screenpipe sync database attachment error","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Last swimming outing with Dani","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Last swimming outing with Dani","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Lukas Pro","depth":15,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Get apps and extensions","depth":15,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Screenpipe data sync and retention management, rename chat","depth":19,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Screenpipe data sync and retention management","depth":21,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"More options for Screenpipe data sync and retention management","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":21,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Share chat","depth":21,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Claude finished the response","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"You said: Lets start from the beginning with the fresh mind.","depth":20,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"You said: Lets start from the beginning with the fresh mind.","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Pasted Text, pasted, 495 lines","depth":21,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"#!/bin/bash # screenpipe_sync.sh # Syncs Screenpipe SQLite data to a NAS archive database (append-only, no deletions). # Also copies the day's video/frame data folder to the NAS. # # Schema-drift tolerant: if Screenpipe migrations add new columns to the source DB, # the NAS archive gets ALTER TABLE'","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PASTED","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Lets start from the beginning with the fresh mind. There is a script for screenpipe to copy data for day from mac to nas. There are two issues I want to work with. Firsts if I reinstall the mac version it starts from fresh id 1. That causes some issues. How to make sure the data are valid. I don't want some overcomplicated flow. I was thinking about making new db every 3 months. Secodn issue is that I wan to implement cleanup (retention policy) on mac original screenpipe db. I want script that will remove data that are 7 days old or older for example. ANd lastly I want to extedn the script to work with audio as well. What od you need","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"20:19","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Retry","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Edit","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Claude responded: Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether…","depth":21,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Claude responded: Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether…","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Analyzed three technical challenges and identified clarifying questions needed","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Analyzed three technical challenges and identified clarifying questions needed","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether reinstalls have already happened). Before I touch the script, a few things:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Issue 1 — ID collisions / archive rotation","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Has a reinstall already happened, or is the current","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"archive.db","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"still from one continuous install? If collisions already exist I need to handle that first; if not, we have a clean slate.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Quarterly rotation works, but it doesn't actually solve reinstalls","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"within","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"a quarter. A cleaner option that I'd lean toward: add an","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"install_id","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"column (UUID generated once and stored in a tiny","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"_meta","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"table in the source DB) to every synced table, and make","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(install_id, id)","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"the logical key. FK joins just gain one extra predicate. Reinstall → new install_id → no collisions, ever. You can still rotate the archive DB quarterly for file-size reasons, but it's no longer load-bearing.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Do you ever run cross-period queries (e.g. \"every frame mentioning JY-20458 across all time\")? That answers whether quarterly sharding is acceptable or whether one growing DB is better.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Issue 2 — Mac-side retention","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Your launch command already has","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"--retention-days 7","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":". Is that not actually deleting anything, or do you want a separate scripted retention you can trust/observe independently?","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Should retention also wipe the matching","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"~/.screenpipe/data/data/YYYY-MM-DD/","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"folders, or only DB rows? (CLI flag does both I believe; a script should match.)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Run order matters: sync writes","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"yesterday","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", retention deletes","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":">7 days old","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— no overlap, but I'd still chain them (sync → retention → log) in one cron entry so a failed sync blocks the delete. OK with that?","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Issue 3 — Audio","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Your current launch flag is","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"--disable-audio","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", so right now there's no audio data to sync. Are you planning to enable it, or is this just to future-proof the script?","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"I need the audio schema. Could you run this and paste the output:","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy to clipboard","depth":27,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"sqlite3 ~/.screenpipe/db.sqlite \".schema\" | grep -iE -A 20 \"audio|transcription\"","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"And:","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ls ~/.screenpipe/data/data/$(date -v-1d +%Y-%m-%d)/ | head","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"so I can see what audio files look like on disk alongside the mp4 frames.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Once I have those, I'll restructure the script in one go rather than piecemeal.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Give positive feedback","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Give negative feedback","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Retry","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"You said: ok lets add install_id.","depth":20,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"You said: ok lets add install_id.","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Pasted Text, pasted, 208 lines","depth":21,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ sqlite3 ~/.screenpipe/db.sqlite \".schema\" | grep -iE -A 20 \"audio|transcription\" CREATE TABLE audio_chunks ( id INTEGER PRIMARY KEY AUTOINCREMENT, file_path TEXT NOT NULL , timestamp TIMESTAMP, sync_id TEXT, machine_id TEXT, synced_at DATETIME, ev","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PASTED","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ok lets add install_id. Lets add separate script deleting data again from data and it should also remove logs and data. Make it manual script for now. I will remove --disable-audio from alias and run it without. I wan to have audio as well. lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ ls ~/.screenpipe/data/data/$(date -v-1d +%Y-%m-%d)/ | head\ncompact_monitor_1_1778411210025.mp4\ncompact_monitor_1_1778413422547.mp4\ncompact_monitor_1_1778436664801.mp4\ncompact_monitor_1_1778437267451.mp4\ncompact_monitor_1_1778437569681.mp4\ncompact_monitor_1_1778437873507.mp4\ncompact_monitor_1_1778438175846.mp4\ncompact_monitor_1_1778438477299.mp4\ncompact_monitor_1_1778438780686.mp4\ncompact_monitor_1_1778439082442.mp4 Inside ~/,screenpipe/data there are data like this ... -rw-r--r-- 1 lukas staff 4628 11 May 16:48 System Audio (output)_2026-05-11_13-48-12.mp4\n-rw-r--r-- 1 lukas staff 4620 11 May 16:48 System Audio (output)_2026-05-11_13-48-34.mp4\n-rw-r--r-- 1 lukas staff 4620 11 May 16:49 System Audio (output)_2026-05-11_13-48-56.mp4\n-rw-r--r-- 1 lukas staff 4628 11 May 16:49 System Audio (output)_2026-05-11_13-49-19.mp4\n-rw-r--r-- 1 lukas staff 4620 11 May 16:50 System Audio (output)_2026-05-11_13-49-41.mp4\n-rw-r--r-- 1 lukas staff 4620 11 May 16:50 System Audio (output)_2026-05-11_13-50-03.mp4\n-rw-r--r-- 1 lukas staff 4628 11 May 16:50 System Audio (output)_2026-05-11_13-50-26.mp4\n-rw-r--r-- 1 lukas staff 4628 11 May 16:51 System Audio (output)_2026-05-11_13-50-48.mp4\n-rw-r--r-- 1 lukas staff 4620 11 May 16:51 System Audio (output)_2026-05-11_13-51-10.mp4\n-rw-r--r-- 1 lukas staff 4620 11 May 16:51 System Audio (output)_2026-05-11_13-51-33.mp4\n-rw-r--r-- 1 lukas staff 4620 11 May 16:52 System Audio (output)_2026-05-11_13-51-55.mp4\ndrwxr-xr-x 9 lukas staff 288 11 May 07:54 data\ndrwxr-xr-x 2 lukas staff 64 11 May 15:48 pending-transcriptions\n-rw-r--r-- 1 lukas staff 29419 10 May 14:11 soundcore AeroClip (input)_2026-05-10_11-10-32.mp4\n-rw-r--r-- 1 lukas staff 56479 10 May 14:11 soundcore AeroClip (input)_2026-05-10_11-11-05.mp4\n-rw-r--r--@ 1 lukas staff 181831 10 May 14:12 soundcore AeroClip (input)_2026-05-10_11-11-35.mp4\n-rw-r--r-- 1 lukas staff 149782 10 May 14:43 soundcore AeroClip (input)_2026-05-10_11-42-53.mp4\n-rw-r--r-- 1 lukas staff 91059 10 May 14:43 soundcore AeroClip (input)_2026-05-10_11-43-25.mp4\n-rw-r--r-- 1 lukas staff 30604 10 May 14:44 soundcore AeroClip (input)_2026-05-10_11-44-25.mp4\n-rw-r--r-- 1 lukas staff 93813 10 May 14:45 soundcore AeroClip (input)_2026-05-10_11-44-55.mp4\n-rw-r--r-- 1 lukas staff 40444 10 May 21:11 soundcore AeroClip (input)_2026-05-10_18-11-18.mp4\n-rw-r--r-- 1 lukas staff 193020 10 May 21:12 soundcore AeroClip (input)_2026-05-10_18-11-48.mp4...","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Show more","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"20:34","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Retry","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Edit","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Claude responded: Good, that clarifies the audio layout — audio files live flat in ~/.","depth":21,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Claude responded: Good, that clarifies the audio layout — audio files live flat in ~/.","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Architected multi-install sync with audio support and retention","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Architected multi-install sync with audio support and retention","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Good, that clarifies the audio layout — audio files live flat in","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"~/.screenpipe/data/","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"with the date in the filename (not in date subdirs like frames), and the schema gives us","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"audio_chunks","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"+","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"audio_transcriptions","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"+","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"speakers","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"+","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"speaker_embeddings","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"+","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"audio_tags","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"plus the FTS table on transcriptions.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Plan I'll implement:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"install_id","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":": stored as a UUID in","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"~/.screenpipe/.sync_install_id","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— disappears when the directory is wiped (which is what you want on reinstall). Every synced NAS table gets an","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"install_id TEXT","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"column and a","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"UNIQUE(install_id, id)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"index. The script auto-migrates the existing NAS archive by adding the column and tagging legacy rows with","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"legacy-YYYYMMDD","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"so historical data is still queryable but doesn't conflict with future installs.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Audio sync","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":": adds","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"audio_chunks","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"audio_transcriptions","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"speakers","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"speaker_embeddings","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"audio_tags","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"to the sync pipeline, plus the","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"audio_transcriptions_fts","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"index. Audio files go to","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"$NAS_DATA/<date>/audio/","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(sibling to the frames in the same date dir, keeps daily archives self-contained).","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Retention","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"is a separate manual script — dry-run by default,","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"--apply","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"to delete. Hits DB rows, frame directories, audio mp4s, and screenpipe logs. Optional","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"--vacuum","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"with a warning (screenpipe must be stopped to avoid blocking writes for minutes).","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"One caveat I'm punting on: the FTS tables use source","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"id","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"as","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"rowid","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", so after a reinstall they'd get id-collisions on insert and","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"INSERT OR IGNORE","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"would silently skip. Within a single install this is fine; after reinstall you'd fall back to","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"LIKE","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"queries on the base tables (still filterable by","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"install_id","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"). I noted this in the script. Fixing it properly needs a synthetic rowid scheme which we can do later if you actually hit it.","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Let me write both:","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Updated screenpipe_sync.sh with install_id support and audio sync","depth":22,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Updated screenpipe_sync.sh with install_id support and audio sync","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Updated screenpipe_sync.sh with install_id support and audio sync","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Updated screenpipe_sync.sh with install_id support and audio sync","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"screenpipe_sync.sh","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Done","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Copy","depth":22,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Give positive feedback","depth":22,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Give negative feedback","depth":22,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Retry","depth":22,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"You said: I don't like that.","depth":20,"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"You said: I don't like that.","depth":21,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"I don't like that. It should be solid without id collisions. Wouldn't it be to late if I should fix it later?","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"20:50","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Retry","depth":22,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Edit","depth":22,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"I don't like that. It should be solid without id collisions. Wouldn't it be to late if I should fix it later?","depth":25,"on_screen":true,"value":"I don't like that. It should be solid without id collisions. Wouldn't it be to late if I should fix it later?","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"I don't like that. It should be solid without id collisions. Wouldn't it be to late if I should fix it later?","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Add files, connectors, and more","depth":27,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Model: Opus 4.7 Adaptive","depth":27,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Opus 4.7","depth":29,"bounds":{"left":0.0,"top":0.0,"width":0.04027778,"height":0.018888889},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Adaptive","depth":28,"bounds":{"left":0.0,"top":0.0,"width":0.041666668,"height":0.018888889},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Send message","depth":26,"bounds":{"left":0.010416667,"top":0.0,"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":"AXLink","text":"Claude is AI and can make mistakes. Please double-check responses.","depth":22,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Claude is AI and can make mistakes. Please double-check responses.","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"Screenpipe sync · SH","depth":19,"on_screen":true,"help_text":"Screenpipe sync","role_description":"heading"},{"role":"AXStaticText","text":"Screenpipe sync","depth":20,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"·","depth":20,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"SH","depth":20,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Copy","depth":19,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":19,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"#!/bin/bash","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# screenpipe_sync.sh","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# Syncs Screenpipe SQLite data (vision + audio) to a NAS archive database.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"4","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# Append-only, no deletions.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"5","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"#","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"6","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# Key design points","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"7","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# -----------------","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"8","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# 1. Multi-install safe via install_id.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"9","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# Source IDs reset to 1 on every screenpipe reinstall. To avoid collisions","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"10","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# in the NAS archive, every synced table gets an extra `install_id` column,","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"11","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# and the logical primary key becomes (install_id, id) enforced by a","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"12","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# unique index. The install_id is a UUID stored in","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"13","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# ~/.screenpipe/.sync_install_id — wiping ~/.screenpipe/ (which is what","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"14","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# happens on reinstall) discards it, so the next run generates a new one.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"15","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"#","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"16","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# 2. Schema-drift tolerant. If screenpipe migrations add new columns to the","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"17","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# source DB, the NAS gets ALTER TABLE'd to match. Inserts use explicit","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"18","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# column lists so positional mismatches can't occur.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"19","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"#","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"20","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# 3. FTS caveat. FTS tables in the NAS use source `id` as rowid. After a","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"21","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# reinstall, INSERT OR IGNORE will silently skip rows whose id collides","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"22","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# with a previous install's id, so FTS only reliably indexes the most","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"23","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# recent install. Falls back to LIKE queries on the base tables for","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"24","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# multi-install searches (which can filter by install_id).","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"25","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"#","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"26","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# Usage","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"27","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# -----","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"28","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# ./screenpipe_sync.sh # syncs yesterday","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"29","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# ./screenpipe_sync.sh 2026-04-15 # syncs a specific date","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"30","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# ./screenpipe_sync.sh today # syncs today so far","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"31","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# ./screenpipe_sync.sh --reset-install-id # rotate install_id and exit","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"32","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# ./screenpipe_sync.sh --show-install-id # print install_id and exit","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"33","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"34","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"set","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"-euo","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"pipefail","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"35","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"36","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# ─── CONFIG ───────────────────────────────────────────────────────────────────","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"37","depth":22,"on_screen":false,"role_description":"text"}]...
|
-8068270864968492631
|
-8490785553493656381
|
click
|
accessibility
|
NULL
|
Skip to content
Skip to content
Click to collapse
Skip to content
Skip to content
Click to collapse
⌘B
Drag to resize
Collapse sidebar
Search
Chat
Cowork
Code
New chat ⌘N
New chat
⌘N
Projects
Artifacts
Customize
Pinned
Bulgarian citizenship application process for EU residents
More options for Bulgarian citizenship application process for EU residents
Dawarich location tracking project
More options for Dawarich location tracking project
Recents
View all
Screenpipe data sync and retention management
More options for Screenpipe data sync and retention management
Screenpipe sync script failing after recent migrations
More options for Screenpipe sync script failing after recent migrations
Hubspot BadRequest headers debugging
More options for Hubspot BadRequest headers debugging
Monthly expense tracking
More options for Monthly expense tracking
Exporting transaction data from Notion to finance hub
More options for Exporting transaction data from Notion to finance hub
💬 How much have I spent for groc…
More options for 💬 How much have I spent for groc…
April 2026 spending by category
More options for April 2026 spending by category
Code diff review
More options for Code diff review
HubSpot rate limit implementation strategy
More options for HubSpot rate limit implementation strategy
Screenpipe retention policy code location
More options for Screenpipe retention policy code location
Viewing retention policy in screenpipe
More options for Viewing retention policy in screenpipe
Clean shot x video recording termination issue
More options for Clean shot x video recording termination issue
HubSpot rate limit handling with executeRequest
More options for HubSpot rate limit handling with executeRequest
Untitled
More options
💬 Screen pipe. Is there ability…
More options for 💬 Screen pipe. Is there ability…
SMB mount access inconsistency between Finder and iTerm
More options for SMB mount access inconsistency between Finder and iTerm
💬 What is the best switch I can…
More options for 💬 What is the best switch I can…
Permission denied on screenpipe volume
More options for Permission denied on screenpipe volume
Screenpipe sync database attachment error
More options for Screenpipe sync database attachment error
Last swimming outing with Dani
More options for Last swimming outing with Dani
Lukas Pro
Get apps and extensions
Screenpipe data sync and retention management, rename chat
Screenpipe data sync and retention management
More options for Screenpipe data sync and retention management
Close
Share chat
Claude finished the response
You said: Lets start from the beginning with the fresh mind.
You said: Lets start from the beginning with the fresh mind.
Pasted Text, pasted, 495 lines
#!/bin/bash # screenpipe_sync.sh # Syncs Screenpipe SQLite data to a NAS archive database (append-only, no deletions). # Also copies the day's video/frame data folder to the NAS. # # Schema-drift tolerant: if Screenpipe migrations add new columns to the source DB, # the NAS archive gets ALTER TABLE'
PASTED
Lets start from the beginning with the fresh mind. There is a script for screenpipe to copy data for day from mac to nas. There are two issues I want to work with. Firsts if I reinstall the mac version it starts from fresh id 1. That causes some issues. How to make sure the data are valid. I don't want some overcomplicated flow. I was thinking about making new db every 3 months. Secodn issue is that I wan to implement cleanup (retention policy) on mac original screenpipe db. I want script that will remove data that are 7 days old or older for example. ANd lastly I want to extedn the script to work with audio as well. What od you need
20:19
Retry
Edit
Copy
Claude responded: Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether…
Claude responded: Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether…
Analyzed three technical challenges and identified clarifying questions needed
Analyzed three technical challenges and identified clarifying questions needed
Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether reinstalls have already happened). Before I touch the script, a few things:
Issue 1 — ID collisions / archive rotation
Has a reinstall already happened, or is the current
archive.db
still from one continuous install? If collisions already exist I need to handle that first; if not, we have a clean slate.
Quarterly rotation works, but it doesn't actually solve reinstalls
within
a quarter. A cleaner option that I'd lean toward: add an
install_id
column (UUID generated once and stored in a tiny
_meta
table in the source DB) to every synced table, and make
(install_id, id)
the logical key. FK joins just gain one extra predicate. Reinstall → new install_id → no collisions, ever. You can still rotate the archive DB quarterly for file-size reasons, but it's no longer load-bearing.
Do you ever run cross-period queries (e.g. "every frame mentioning JY-20458 across all time")? That answers whether quarterly sharding is acceptable or whether one growing DB is better.
Issue 2 — Mac-side retention
Your launch command already has
--retention-days 7
. Is that not actually deleting anything, or do you want a separate scripted retention you can trust/observe independently?
Should retention also wipe the matching
~/.screenpipe/data/data/YYYY-MM-DD/
folders, or only DB rows? (CLI flag does both I believe; a script should match.)
Run order matters: sync writes
yesterday
, retention deletes
>7 days old
— no overlap, but I'd still chain them (sync → retention → log) in one cron entry so a failed sync blocks the delete. OK with that?
Issue 3 — Audio
Your current launch flag is
--disable-audio
, so right now there's no audio data to sync. Are you planning to enable it, or is this just to future-proof the script?
I need the audio schema. Could you run this and paste the output:
Copy to clipboard
sqlite3 ~/.screenpipe/db.sqlite ".schema" | grep -iE -A 20 "audio|transcription"
And:
ls ~/.screenpipe/data/data/$(date -v-1d +%Y-%m-%d)/ | head
so I can see what audio files look like on disk alongside the mp4 frames.
Once I have those, I'll restructure the script in one go rather than piecemeal.
Copy
Give positive feedback
Give negative feedback
Retry
You said: ok lets add install_id.
You said: ok lets add install_id.
Pasted Text, pasted, 208 lines
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ sqlite3 ~/.screenpipe/db.sqlite ".schema" | grep -iE -A 20 "audio|transcription" CREATE TABLE audio_chunks ( id INTEGER PRIMARY KEY AUTOINCREMENT, file_path TEXT NOT NULL , timestamp TIMESTAMP, sync_id TEXT, machine_id TEXT, synced_at DATETIME, ev
PASTED
ok lets add install_id. Lets add separate script deleting data again from data and it should also remove logs and data. Make it manual script for now. I will remove --disable-audio from alias and run it without. I wan to have audio as well. lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ ls ~/.screenpipe/data/data/$(date -v-1d +%Y-%m-%d)/ | head
compact_monitor_1_1778411210025.mp4
compact_monitor_1_1778413422547.mp4
compact_monitor_1_1778436664801.mp4
compact_monitor_1_1778437267451.mp4
compact_monitor_1_1778437569681.mp4
compact_monitor_1_1778437873507.mp4
compact_monitor_1_1778438175846.mp4
compact_monitor_1_1778438477299.mp4
compact_monitor_1_1778438780686.mp4
compact_monitor_1_1778439082442.mp4 Inside ~/,screenpipe/data there are data like this ... -rw-r--r-- 1 lukas staff 4628 11 May 16:48 System Audio (output)_2026-05-11_13-48-12.mp4
-rw-r--r-- 1 lukas staff 4620 11 May 16:48 System Audio (output)_2026-05-11_13-48-34.mp4
-rw-r--r-- 1 lukas staff 4620 11 May 16:49 System Audio (output)_2026-05-11_13-48-56.mp4
-rw-r--r-- 1 lukas staff 4628 11 May 16:49 System Audio (output)_2026-05-11_13-49-19.mp4
-rw-r--r-- 1 lukas staff 4620 11 May 16:50 System Audio (output)_2026-05-11_13-49-41.mp4
-rw-r--r-- 1 lukas staff 4620 11 May 16:50 System Audio (output)_2026-05-11_13-50-03.mp4
-rw-r--r-- 1 lukas staff 4628 11 May 16:50 System Audio (output)_2026-05-11_13-50-26.mp4
-rw-r--r-- 1 lukas staff 4628 11 May 16:51 System Audio (output)_2026-05-11_13-50-48.mp4
-rw-r--r-- 1 lukas staff 4620 11 May 16:51 System Audio (output)_2026-05-11_13-51-10.mp4
-rw-r--r-- 1 lukas staff 4620 11 May 16:51 System Audio (output)_2026-05-11_13-51-33.mp4
-rw-r--r-- 1 lukas staff 4620 11 May 16:52 System Audio (output)_2026-05-11_13-51-55.mp4
drwxr-xr-x 9 lukas staff 288 11 May 07:54 data
drwxr-xr-x 2 lukas staff 64 11 May 15:48 pending-transcriptions
-rw-r--r-- 1 lukas staff 29419 10 May 14:11 soundcore AeroClip (input)_2026-05-10_11-10-32.mp4
-rw-r--r-- 1 lukas staff 56479 10 May 14:11 soundcore AeroClip (input)_2026-05-10_11-11-05.mp4
-rw-r--r--@ 1 lukas staff 181831 10 May 14:12 soundcore AeroClip (input)_2026-05-10_11-11-35.mp4
-rw-r--r-- 1 lukas staff 149782 10 May 14:43 soundcore AeroClip (input)_2026-05-10_11-42-53.mp4
-rw-r--r-- 1 lukas staff 91059 10 May 14:43 soundcore AeroClip (input)_2026-05-10_11-43-25.mp4
-rw-r--r-- 1 lukas staff 30604 10 May 14:44 soundcore AeroClip (input)_2026-05-10_11-44-25.mp4
-rw-r--r-- 1 lukas staff 93813 10 May 14:45 soundcore AeroClip (input)_2026-05-10_11-44-55.mp4
-rw-r--r-- 1 lukas staff 40444 10 May 21:11 soundcore AeroClip (input)_2026-05-10_18-11-18.mp4
-rw-r--r-- 1 lukas staff 193020 10 May 21:12 soundcore AeroClip (input)_2026-05-10_18-11-48.mp4...
Show more
20:34
Retry
Edit
Copy
Claude responded: Good, that clarifies the audio layout — audio files live flat in ~/.
Claude responded: Good, that clarifies the audio layout — audio files live flat in ~/.
Architected multi-install sync with audio support and retention
Architected multi-install sync with audio support and retention
Good, that clarifies the audio layout — audio files live flat in
~/.screenpipe/data/
with the date in the filename (not in date subdirs like frames), and the schema gives us
audio_chunks
+
audio_transcriptions
+
speakers
+
speaker_embeddings
+
audio_tags
plus the FTS table on transcriptions.
Plan I'll implement:
install_id
: stored as a UUID in
~/.screenpipe/.sync_install_id
— disappears when the directory is wiped (which is what you want on reinstall). Every synced NAS table gets an
install_id TEXT
column and a
UNIQUE(install_id, id)
index. The script auto-migrates the existing NAS archive by adding the column and tagging legacy rows with
legacy-YYYYMMDD
so historical data is still queryable but doesn't conflict with future installs.
Audio sync
: adds
audio_chunks
,
audio_transcriptions
,
speakers
,
speaker_embeddings
,
audio_tags
to the sync pipeline, plus the
audio_transcriptions_fts
index. Audio files go to
$NAS_DATA/<date>/audio/
(sibling to the frames in the same date dir, keeps daily archives self-contained).
Retention
is a separate manual script — dry-run by default,
--apply
to delete. Hits DB rows, frame directories, audio mp4s, and screenpipe logs. Optional
--vacuum
with a warning (screenpipe must be stopped to avoid blocking writes for minutes).
One caveat I'm punting on: the FTS tables use source
id
as
rowid
, so after a reinstall they'd get id-collisions on insert and
INSERT OR IGNORE
would silently skip. Within a single install this is fine; after reinstall you'd fall back to
LIKE
queries on the base tables (still filterable by
install_id
). I noted this in the script. Fixing it properly needs a synthetic rowid scheme which we can do later if you actually hit it.
Let me write both:
Updated screenpipe_sync.sh with install_id support and audio sync
Updated screenpipe_sync.sh with install_id support and audio sync
Updated screenpipe_sync.sh with install_id support and audio sync
Updated screenpipe_sync.sh with install_id support and audio sync
screenpipe_sync.sh
Done
Copy
Give positive feedback
Give negative feedback
Retry
You said: I don't like that.
You said: I don't like that.
I don't like that. It should be solid without id collisions. Wouldn't it be to late if I should fix it later?
20:50
Retry
Edit
Copy
I don't like that. It should be solid without id collisions. Wouldn't it be to late if I should fix it later?
I don't like that. It should be solid without id collisions. Wouldn't it be to late if I should fix it later?
Add files, connectors, and more
Model: Opus 4.7 Adaptive
Opus 4.7
Adaptive
Send message
Claude is AI and can make mistakes. Please double-check responses.
Claude is AI and can make mistakes. Please double-check responses.
Screenpipe sync · SH
Screenpipe sync
·
SH
Copy
Close
1
#!/bin/bash
2
# screenpipe_sync.sh
3
# Syncs Screenpipe SQLite data (vision + audio) to a NAS archive database.
4
# Append-only, no deletions.
5
#
6
# Key design points
7
# -----------------
8
# 1. Multi-install safe via install_id.
9
# Source IDs reset to 1 on every screenpipe reinstall. To avoid collisions
10
# in the NAS archive, every synced table gets an extra `install_id` column,
11
# and the logical primary key becomes (install_id, id) enforced by a
12
# unique index. The install_id is a UUID stored in
13
# ~/.screenpipe/.sync_install_id — wiping ~/.screenpipe/ (which is what
14
# happens on reinstall) discards it, so the next run generates a new one.
15
#
16
# 2. Schema-drift tolerant. If screenpipe migrations add new columns to the
17
# source DB, the NAS gets ALTER TABLE'd to match. Inserts use explicit
18
# column lists so positional mismatches can't occur.
19
#
20
# 3. FTS caveat. FTS tables in the NAS use source `id` as rowid. After a
21
# reinstall, INSERT OR IGNORE will silently skip rows whose id collides
22
# with a previous install's id, so FTS only reliably indexes the most
23
# recent install. Falls back to LIKE queries on the base tables for
24
# multi-install searches (which can filter by install_id).
25
#
26
# Usage
27
# -----
28
# ./screenpipe_sync.sh # syncs yesterday
29
# ./screenpipe_sync.sh 2026-04-15 # syncs a specific date
30
# ./screenpipe_sync.sh today # syncs today so far
31
# ./screenpipe_sync.sh --reset-install-id # rotate install_id and exit
32
# ./screenpipe_sync.sh --show-install-id # print install_id and exit
33
34
set
-euo
pipefail
35
36
# ─── CONFIG ───────────────────────────────────────────────────────────────────
37...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
16359
|
734
|
5
|
2026-05-11T08:46:06.967962+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778489166967_m1.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEdit ViewGoHistoryWindowHelpDOCKER-₴81DEV SlackFileEdit ViewGoHistoryWindowHelpDOCKER-₴81DEV (docker)882DEV (d)APP (-zsh)• xзmasterJY-20818-move-AJ-reports-to-separated-datadog-metricJY-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]@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-Lirroot@docker_lamp_1:/home/jiminny# ]•HomeDMsActivityFilesLater..•More(wb)§ Support Daily • in 3 h 14 m100% <78• Mon 11 May 11:46:06ED→Describe what you are looking forJiminny ...Chsmechuus# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...# releases8 226 0• Messages+• Direct messagesa. Stefka Stoyano...€. Vasil VasilevNikolay Ivanov. Galya DimitrovaAneliya Angelova, .... Stoyan Tanev@ Ves®. Aneliya Angelova& James GrahamLukas Kovalik y…..::: AppsC FilesBookmarksclaude-great-arToday~Show more(jiminny/app Added by GitHubCircleCl APP 10:35 AMDeployment Successful!Project: appWhen:05/11/202607:35:21Tag:View JobNewToastJira CloudGoogle Cale...CircleCl APP11:00 AMNew commits deployed to Prophet Prod-US:[e568c4f](https://github.com/jiminny/prophet/commit/e568c4f3b57c9392883f81974b6db3dd09a23a1e) - [JY-20832](https://jiminny.atlassian.net/browse/JY-20832): Remove usage of grok 4.0 and 4.1 models(#506) (steliyan-g)New commits deployed to Prophet Prod-EU:[e568c4f](https://github.com/jiminny/prophet/commit/e568c4f3b57c9392883f81974b6db3dd09a23ale)- [JY-20832](https://jiminny.atlassian.net/browse/JY-20832): Remove usage of grok 4.0 and 4.1 models(#506) (steliyan-g)Message #releases1+Aa..•...
|
NULL
|
-8068267664371381448
|
NULL
|
click
|
ocr
|
NULL
|
SlackFileEdit ViewGoHistoryWindowHelpDOCKER-₴81DEV SlackFileEdit ViewGoHistoryWindowHelpDOCKER-₴81DEV (docker)882DEV (d)APP (-zsh)• xзmasterJY-20818-move-AJ-reports-to-separated-datadog-metricJY-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]@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-Lirroot@docker_lamp_1:/home/jiminny# ]•HomeDMsActivityFilesLater..•More(wb)§ Support Daily • in 3 h 14 m100% <78• Mon 11 May 11:46:06ED→Describe what you are looking forJiminny ...Chsmechuus# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...# releases8 226 0• Messages+• Direct messagesa. Stefka Stoyano...€. Vasil VasilevNikolay Ivanov. Galya DimitrovaAneliya Angelova, .... Stoyan Tanev@ Ves®. Aneliya Angelova& James GrahamLukas Kovalik y…..::: AppsC FilesBookmarksclaude-great-arToday~Show more(jiminny/app Added by GitHubCircleCl APP 10:35 AMDeployment Successful!Project: appWhen:05/11/202607:35:21Tag:View JobNewToastJira CloudGoogle Cale...CircleCl APP11:00 AMNew commits deployed to Prophet Prod-US:[e568c4f](https://github.com/jiminny/prophet/commit/e568c4f3b57c9392883f81974b6db3dd09a23a1e) - [JY-20832](https://jiminny.atlassian.net/browse/JY-20832): Remove usage of grok 4.0 and 4.1 models(#506) (steliyan-g)New commits deployed to Prophet Prod-EU:[e568c4f](https://github.com/jiminny/prophet/commit/e568c4f3b57c9392883f81974b6db3dd09a23ale)- [JY-20832](https://jiminny.atlassian.net/browse/JY-20832): Remove usage of grok 4.0 and 4.1 models(#506) (steliyan-g)Message #releases1+Aa..•...
|
16357
|
NULL
|
NULL
|
NULL
|
|
24325
|
1017
|
21
|
2026-05-12T09:04:01.898345+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-12/1778 /Users/lukas/.screenpipe/data/data/2026-05-12/1778576641898_m2.jpg...
|
Firefox
|
(172) Papa Juan Pablo II hablando en 13 Idiomas - (172) Papa Juan Pablo II hablando en 13 Idiomas - YouTube — Personal...
|
True
|
www.youtube.com/watch?v=apLRKbprP54
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
New Tab
New Tab
Screenpipe — Archive
Screenpipe — New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
All docs · AFFiNE
All docs · AFFiNE
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
(172) Papa Juan Pablo II hablando en 13 Idiomas - YouTube
Mute tab
(172) Papa Juan Pablo II hablando en 13 Idiomas - YouTube
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Sprievodca
Domovská stránka YouTube
BG
Preskočiť navigáciu
Preskočiť navigáciu
Karol Wojtyla speaking langauges
Karol Wojtyla speaking langauges
Vymazať vyhľadávací dopyt
Search
Vyhľadávať hlasom
Vytvoriť
Vytvoriť
Upozornenia
9+
Ponuka účtu
Zobraziť karty
Vodoznak kanála
Prehrávanie (k)
Stlmiť (m)
0 min 48 s z 5 min 42 s
0:48
/
5:42
Automatické prehrávanie je zapnuté
Titulky alebo skryté titulky sú nedostupné
Nastavenia
Režim kina (t)
Celá obrazovka (f)
Papa Juan Pablo II hablando en 13 Idiomas
Papa Juan Pablo II hablando en 13 Idiomas
Manoloyy
Manoloyy
124 tis. odberateľov
Prihlásiť sa na odber kanála Manoloyy.
Odoberať
Označiť, že sa mi toto video páči, tak ako 7 562 ďalším osobám
7,5 tis.
Toto video sa mi nepáči
Zdieľať
Zdieľať
Uložiť do zoznamu
Uložiť
Ďalšie akcie
350 tis. zhliadnutí
pred 8 rokmi
El Papa Juan Pablo II (Karol Wojtyla) hablando en inglés, español, alemán, portugués, francés, italiano, ruso, japonés, croata, checo, ucraniano, latín y polaco
...viac
...viac
916 komentárov
916
komentárov
Zoradiť komentáre
Zoradiť podľa
Pridajte komentár…
@danielnainggolan6258
@danielnainggolan6258
@danielnainggolan6258
@danielnainggolan6258
pred 1 rokom
pred 1 rokom
0:03
0:03
English/Inglés 🇬🇧
0:33
0:33
Spanish/idioma español 🇪🇸
1:07
1:07
German/idioma alemán 🇩🇪
1:35
1:35
Portuguese/Portugués 🇵🇹
1:55
1:55
French/Francés 🇫🇷
2:18
2:18
Italian/italiano 🇮🇹
2:52
2:52
Russian/idioma ruso 🇷🇺
3:15
3:15
Japanese/Japonés 🇯🇵
3:33
3:33
Croatian/idioma croata
4:01
4:01
Czech/Idioma checo 🇨🇿
4:34
4:34
Ukranian/Ucraniano 🇺🇦
5:00
5:00
Latin/latín 🇻🇦
5:24
5:24
Polish/polaco 🇵🇱
Zobraziť viac
Preložiť do jazyka angličtina
Označiť, že sa vám tento komentár páči, tak ako 57 ďalším ľuďom
57
Tento komentár sa mi nepáči
Odpovedať
Odpovedať
Ponuka akcií
@Flori-an
@Flori-an
@Flori-an
@Flori-an
pred 2 rokmi
pred 2 rokmi
It is really impressive how much effort he has made to always know at least a few sentences in the language corresponding to the country he has visited. The words always sound clear, and his voice is absolutely unmistakable anyway. :)
Označiť, že sa vám tento komentár páči, tak ako 119 ďalším ľuďom
119
Tento komentár sa mi nepáči
Odpovedať
Odpovedať
Ponuka akcií
1 odpoveď
1 odpoveď
@Chavezoid
@Chavezoid
@Chavezoid
@Chavezoid
pred 6 rokmi
pred 6 rokmi
Wow, his Polish is flawless, even sounds native.
Označiť, že sa vám tento komentár páči, tak ako 807 ďalším ľuďom
807
Tento komentár sa mi nepáči
Odpovedať
Odpovedať
Ponuka akcií
65 odpovedí
65 odpovedí
@diegoboatman3196
@diegoboatman3196
@diegoboatman3196
@diegoboatman3196
pred 5 rokmi
pred 5 rokmi
Juan Pablo II ha sido el más grande de todos los papas, logró unir al mundo.
Preložiť do jazyka angličtina
Označiť, že sa vám tento komentár páči, tak ako 32 ďalším ľuďom
32
Tento komentár sa mi nepáči
Odpovedať
Odpovedať
Ponuka akcií
@luistorresalcantara5270
@luistorresalcantara5270
@luistorresalcantara5270
@luistorresalcantara5270
pred 5 rokmi
pred 5 rokmi
Este hombre era un sabio, es increíble.
Preložiť do jazyka angličtina
Označiť, že sa vám tento komentár páči, tak ako 67 ďalším ľuďom
67
Tento komentár sa mi nepáči
Odpovedať
Odpovedať
Ponuka akcií
@karinaflores254
@karinaflores254
@karinaflores254
@karinaflores254
pred 5 rokmi (upravené)
pred 5 rokmi (upravené)
Yo estoy estudiando ingles y francés, ya casi llevo 2 años y no los domino. Es impresionante que este Papa haya hablado 13 idiomas y quizás más
Preložiť do jazyka angličtina
Označiť, že sa vám tento komentár páči, tak ako 233 ďalším ľuďom
233
Tento komentár sa mi nepáči
Odpovedať
Odpovedať
Ponuka akcií
14 odpovedí
14 odpovedí
@sky_idk7
@sky_idk7
@sky_idk7
@sky_idk7
pred 1 rokom (upravené)
pred 1 rokom (upravené)
Su español era muy muy bueno. Aunque en el vídeo, el papa ya estaba muy mayor y enfermo, cuando era más joven lo hablaba perfecto. Se nota que dominaba el idioma porque no sólo lo he escuchado decir discursos leyendo, sino que él sabía improvisar e incluso hacer bromas. Era re carismático y encantador.
Preložiť do jazyka angličtina
Označiť, že sa vám tento komentár páči, tak ako 27 ďalším ľuďom
27
Tento komentár sa mi nepáči
Odpovedať
Odpovedať
Ponuka akcií
@marcioe.7579
@marcioe.7579
@marcioe.7579
@marcioe.7579
pred 1 rokom
pred 1 rokom
O papa falava 16 idiomas. É impressionante como eles conseguem dominar tudo isso.
Preložiť do jazyka angličtina
Označiť, že sa vám tento komentár páči, tak ako 6 ďalším ľuďom
6
Tento komentár sa mi nepáči
Odpovedať
Odpovedať
Ponuka akcií
@owlieo.3432
@owlieo.3432
@owlieo.3432
@owlieo.3432
pred 1 rokom
pred 1 rokom
Que homem extraordinário!
Preložiť do jazyka angličtina
Označiť, že sa vám tento komentár páči, tak ako 17 ďalším ľuďom
17
Tento komentár sa mi nepáči
Odpovedať
Odpovedať
Ponuka akcií...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.5,"top":0.0518755,"width":0.06881649,"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.51329786,"top":0.06304868,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.5,"top":0.08459697,"width":0.06881649,"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.51329786,"top":0.09577015,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"All docs · AFFiNE","depth":4,"bounds":{"left":0.5,"top":0.11731844,"width":0.06881649,"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":"All docs · AFFiNE","depth":5,"bounds":{"left":0.51329786,"top":0.12849163,"width":0.029587766,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"bounds":{"left":0.5,"top":0.15003991,"width":0.06881649,"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.51329786,"top":0.16121309,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.5,"top":0.18276137,"width":0.06881649,"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.51329786,"top":0.19393456,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.5,"top":0.21548285,"width":0.06881649,"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.51329786,"top":0.22665602,"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.5,"top":0.2482043,"width":0.06881649,"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.51329786,"top":0.25937748,"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.5,"top":0.28092578,"width":0.06881649,"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.51329786,"top":0.29209897,"width":0.03756649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"(172) Papa Juan Pablo II hablando en 13 Idiomas - YouTube","depth":4,"bounds":{"left":0.5,"top":0.31364724,"width":0.06881649,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXButton","text":"Mute tab","depth":5,"bounds":{"left":0.5114694,"top":0.32083002,"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":"AXStaticText","text":"(172) Papa Juan Pablo II hablando en 13 Idiomas - YouTube","depth":5,"bounds":{"left":0.52011305,"top":0.32482043,"width":0.1022274,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.55651593,"top":0.32083002,"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.5028258,"top":0.34796488,"width":0.06333112,"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.5028258,"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.51379657,"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.5249335,"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.53607047,"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.5472075,"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":"Sprievodca","depth":13,"bounds":{"left":0.5767952,"top":0.06464485,"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":"AXLink","text":"Domovská stránka YouTube","depth":12,"bounds":{"left":0.5874335,"top":0.0518755,"width":0.04089096,"height":0.044692736},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"BG","depth":13,"bounds":{"left":0.625,"top":0.061452515,"width":0.0043218085,"height":0.009577015},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Preskočiť navigáciu","depth":14,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Preskočiť navigáciu","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXComboBox","text":"Karol Wojtyla speaking langauges","depth":15,"bounds":{"left":0.6843417,"top":0.06464485,"width":0.15292554,"height":0.01915403},"on_screen":true,"value":"Karol Wojtyla speaking langauges","help_text":"","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Karol Wojtyla speaking langauges","depth":16,"bounds":{"left":0.6843417,"top":0.066640064,"width":0.07945479,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Vymazať vyhľadávací dopyt","depth":14,"bounds":{"left":0.84491354,"top":0.058260176,"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},{"role":"AXButton","text":"Search","depth":13,"bounds":{"left":0.8568817,"top":0.058260176,"width":0.021276595,"height":0.031923383},"on_screen":true,"help_text":"Hľadať","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Vyhľadávať hlasom","depth":14,"bounds":{"left":0.8834774,"top":0.058260176,"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},{"role":"AXButton","text":"Vytvoriť","depth":14,"bounds":{"left":0.923371,"top":0.059856344,"width":0.03474069,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Vytvoriť","depth":17,"bounds":{"left":0.9366689,"top":0.06783719,"width":0.016123671,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Upozornenia","depth":15,"bounds":{"left":0.96077126,"top":0.058260176,"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},{"role":"AXStaticText","text":"9+","depth":17,"bounds":{"left":0.9694149,"top":0.06384677,"width":0.004488032,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Ponuka účtu","depth":14,"bounds":{"left":0.97672874,"top":0.060654428,"width":0.017952127,"height":0.027134877},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Zobraziť karty","depth":19,"bounds":{"left":0.83976066,"top":0.10774142,"width":0.011968086,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Vodoznak kanála","depth":19,"bounds":{"left":0.8384308,"top":0.3858739,"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},{"role":"AXButton","text":"Prehrávanie (k)","depth":20,"bounds":{"left":0.578125,"top":0.44333598,"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},{"role":"AXButton","text":"Stlmiť (m)","depth":21,"bounds":{"left":0.59541225,"top":0.44333598,"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},{"role":"AXButton","text":"0 min 48 s z 5 min 42 s","depth":22,"bounds":{"left":0.6402925,"top":0.44333598,"width":0.022273935,"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":"0:48","depth":23,"bounds":{"left":0.6402925,"top":0.45251396,"width":0.009142287,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":23,"bounds":{"left":0.64943486,"top":0.45251396,"width":0.0043218085,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5:42","depth":23,"bounds":{"left":0.6537567,"top":0.45251396,"width":0.00880984,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Automatické prehrávanie je zapnuté","depth":19,"bounds":{"left":0.7706117,"top":0.44333598,"width":0.015957447,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Titulky alebo skryté titulky sú nedostupné","depth":19,"bounds":{"left":0.7865692,"top":0.44333598,"width":0.015957447,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Nastavenia","depth":19,"bounds":{"left":0.8025266,"top":0.44333598,"width":0.015957447,"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":"AXButton","text":"Režim kina (t)","depth":19,"bounds":{"left":0.81848407,"top":0.44333598,"width":0.015957447,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Celá obrazovka (f)","depth":19,"bounds":{"left":0.8344415,"top":0.44333598,"width":0.015957447,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Papa Juan Pablo II hablando en 13 Idiomas","depth":16,"bounds":{"left":0.57413566,"top":0.49122107,"width":0.28158244,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Papa Juan Pablo II hablando en 13 Idiomas","depth":18,"bounds":{"left":0.57413566,"top":0.49281725,"width":0.12882313,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Manoloyy","depth":22,"bounds":{"left":0.59142286,"top":0.5207502,"width":0.023603724,"height":0.017557861},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Manoloyy","depth":23,"bounds":{"left":0.59142286,"top":0.5219473,"width":0.023105053,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"124 tis. odberateľov","depth":20,"bounds":{"left":0.59142286,"top":0.53990424,"width":0.03523936,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Prihlásiť sa na odber kanála Manoloyy.","depth":20,"bounds":{"left":0.6359708,"top":0.5223464,"width":0.029920213,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Odoberať","depth":23,"bounds":{"left":0.6412899,"top":0.5303272,"width":0.019281914,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Označiť, že sa mi toto video páči, tak ako 7 562 ďalším osobám","depth":24,"bounds":{"left":0.7219083,"top":0.5223464,"width":0.032579787,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7,5 tis.","depth":26,"bounds":{"left":0.7352061,"top":0.5303272,"width":0.013962766,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Toto video sa mi nepáči","depth":24,"bounds":{"left":0.75448805,"top":0.5223464,"width":0.017287234,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Zdieľať","depth":22,"bounds":{"left":0.77443486,"top":0.5223464,"width":0.033410903,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Zdieľať","depth":24,"bounds":{"left":0.7877327,"top":0.5303272,"width":0.014793883,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Uložiť do zoznamu","depth":22,"bounds":{"left":0.81050533,"top":0.5223464,"width":0.030585106,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Uložiť","depth":24,"bounds":{"left":0.8238032,"top":0.5303272,"width":0.011968086,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Ďalšie akcie","depth":20,"bounds":{"left":0.84375,"top":0.5223464,"width":0.011968086,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"350 tis. zhliadnutí","depth":21,"bounds":{"left":0.578125,"top":0.57422185,"width":0.03706782,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"pred 8 rokmi","depth":21,"bounds":{"left":0.61752,"top":0.57422185,"width":0.026097074,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"El Papa Juan Pablo II (Karol Wojtyla) hablando en inglés, español, alemán, portugués, francés, italiano, ruso, japonés, croata, checo, ucraniano, latín y polaco","depth":21,"bounds":{"left":0.578125,"top":0.59018356,"width":0.2706117,"height":0.029130088},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"...viac","depth":19,"bounds":{"left":0.6293218,"top":0.6049481,"width":0.013297873,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...viac","depth":20,"bounds":{"left":0.62982047,"top":0.60614526,"width":0.012300532,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"916 komentárov","depth":19,"bounds":{"left":0.57413566,"top":0.64964086,"width":0.04870346,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"916","depth":21,"bounds":{"left":0.57413566,"top":0.651237,"width":0.011469414,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"komentárov","depth":21,"bounds":{"left":0.585605,"top":0.651237,"width":0.03723404,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Zoradiť komentáre","depth":24,"bounds":{"left":0.6334774,"top":0.64884275,"width":0.040724736,"height":0.01915403},"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":"Zoradiť podľa","depth":26,"bounds":{"left":0.6441157,"top":0.6520351,"width":0.030086435,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Pridajte komentár…","depth":19,"bounds":{"left":0.58610374,"top":0.6923384,"width":0.039727394,"height":0.0131683955},"on_screen":true,"value":"Pridajte komentár…","help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"@danielnainggolan6258","depth":21,"bounds":{"left":0.57413566,"top":0.7366321,"width":0.011968086,"height":0.0311253},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"@danielnainggolan6258","depth":23,"bounds":{"left":0.59142286,"top":0.7366321,"width":0.048204787,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"@danielnainggolan6258","depth":24,"bounds":{"left":0.59142286,"top":0.7366321,"width":0.046875,"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":"@danielnainggolan6258","depth":25,"bounds":{"left":0.59142286,"top":0.73743016,"width":0.046875,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"pred 1 rokom","depth":24,"bounds":{"left":0.63962764,"top":0.7366321,"width":0.0234375,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"pred 1 rokom","depth":25,"bounds":{"left":0.63962764,"top":0.73822826,"width":0.0234375,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0:03","depth":23,"bounds":{"left":0.59142286,"top":0.75538707,"width":0.008976064,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0:03","depth":24,"bounds":{"left":0.59142286,"top":0.75538707,"width":0.008976064,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"English/Inglés 🇬🇧","depth":23,"bounds":{"left":0.60039896,"top":0.75458896,"width":0.036402926,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0:33","depth":23,"bounds":{"left":0.59142286,"top":0.7713488,"width":0.008976064,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0:33","depth":24,"bounds":{"left":0.59142286,"top":0.7713488,"width":0.008976064,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Spanish/idioma español 🇪🇸","depth":23,"bounds":{"left":0.60039896,"top":0.77055067,"width":0.05718085,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1:07","depth":23,"bounds":{"left":0.59142286,"top":0.7873105,"width":0.008976064,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1:07","depth":24,"bounds":{"left":0.59142286,"top":0.7873105,"width":0.008976064,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"German/idioma alemán 🇩🇪","depth":23,"bounds":{"left":0.60039896,"top":0.7865124,"width":0.055851065,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1:35","depth":23,"bounds":{"left":0.59142286,"top":0.8032721,"width":0.008976064,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1:35","depth":24,"bounds":{"left":0.59142286,"top":0.8032721,"width":0.008976064,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Portuguese/Portugués 🇵🇹","depth":23,"bounds":{"left":0.60039896,"top":0.8024741,"width":0.05418883,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1:55","depth":23,"bounds":{"left":0.59142286,"top":0.81923383,"width":0.008976064,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1:55","depth":24,"bounds":{"left":0.59142286,"top":0.81923383,"width":0.008976064,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"French/Francés 🇫🇷","depth":23,"bounds":{"left":0.60039896,"top":0.8184357,"width":0.03939495,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2:18","depth":23,"bounds":{"left":0.59142286,"top":0.83519554,"width":0.008976064,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2:18","depth":24,"bounds":{"left":0.59142286,"top":0.83519554,"width":0.008976064,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Italian/italiano 🇮🇹","depth":23,"bounds":{"left":0.60039896,"top":0.83439744,"width":0.03673537,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2:52","depth":23,"bounds":{"left":0.59142286,"top":0.85115725,"width":0.008976064,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2:52","depth":24,"bounds":{"left":0.59142286,"top":0.85115725,"width":0.008976064,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Russian/idioma ruso 🇷🇺","depth":23,"bounds":{"left":0.60039896,"top":0.85035914,"width":0.049867023,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"3:15","depth":23,"bounds":{"left":0.59142286,"top":0.8671189,"width":0.008976064,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3:15","depth":24,"bounds":{"left":0.59142286,"top":0.8671189,"width":0.008976064,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Japanese/Japonés 🇯🇵","depth":23,"bounds":{"left":0.60039896,"top":0.86632085,"width":0.046875,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"3:33","depth":23,"bounds":{"left":0.59142286,"top":0.8830806,"width":0.008976064,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3:33","depth":24,"bounds":{"left":0.59142286,"top":0.8830806,"width":0.008976064,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Croatian/idioma croata","depth":23,"bounds":{"left":0.60039896,"top":0.8830806,"width":0.050199468,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"4:01","depth":23,"bounds":{"left":0.59142286,"top":0.8990423,"width":0.008976064,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4:01","depth":24,"bounds":{"left":0.59142286,"top":0.8990423,"width":0.008976064,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Czech/Idioma checo 🇨🇿","depth":23,"bounds":{"left":0.60039896,"top":0.8982442,"width":0.049700797,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"4:34","depth":23,"bounds":{"left":0.59142286,"top":0.915004,"width":0.008976064,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4:34","depth":24,"bounds":{"left":0.59142286,"top":0.915004,"width":0.008976064,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ukranian/Ucraniano 🇺🇦","depth":23,"bounds":{"left":0.60039896,"top":0.9142059,"width":0.048038565,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"5:00","depth":23,"bounds":{"left":0.59142286,"top":0.93096566,"width":0.008976064,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5:00","depth":24,"bounds":{"left":0.59142286,"top":0.93096566,"width":0.008976064,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Latin/latín 🇻🇦","depth":23,"bounds":{"left":0.60039896,"top":0.9301676,"width":0.028091755,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"5:24","depth":23,"bounds":{"left":0.59142286,"top":0.94692737,"width":0.008976064,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5:24","depth":24,"bounds":{"left":0.59142286,"top":0.94692737,"width":0.008976064,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Polish/polaco 🇵🇱","depth":23,"bounds":{"left":0.60039896,"top":0.94612926,"width":0.035738032,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Zobraziť viac","depth":22,"bounds":{"left":0.59142286,"top":0.82122904,"width":0.026928192,"height":0.015961692},"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":"Preložiť do jazyka angličtina","depth":22,"bounds":{"left":0.59142286,"top":0.84038305,"width":0.058344416,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Označiť, že sa vám tento komentár páči, tak ako 57 ďalším ľuďom","depth":24,"bounds":{"left":0.5887633,"top":0.8595371,"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":"57","depth":24,"bounds":{"left":0.5994016,"top":0.86632085,"width":0.004488032,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Tento komentár sa mi nepáči","depth":24,"bounds":{"left":0.6065492,"top":0.8595371,"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":"Odpovedať","depth":24,"bounds":{"left":0.61984706,"top":0.8595371,"width":0.027426861,"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":"Odpovedať","depth":27,"bounds":{"left":0.62383646,"top":0.86632085,"width":0.019448139,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Ponuka akcií","depth":22,"bounds":{"left":0.8424202,"top":0.7270551,"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},{"role":"AXButton","text":"@Flori-an","depth":21,"bounds":{"left":0.57413566,"top":0.89784515,"width":0.011968086,"height":0.0311253},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"@Flori-an","depth":23,"bounds":{"left":0.59142286,"top":0.89784515,"width":0.019946808,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"@Flori-an","depth":24,"bounds":{"left":0.59142286,"top":0.89784515,"width":0.01861702,"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":"@Flori-an","depth":25,"bounds":{"left":0.59142286,"top":0.89864326,"width":0.01861702,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"pred 2 rokmi","depth":24,"bounds":{"left":0.61136967,"top":0.89784515,"width":0.022273935,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"pred 2 rokmi","depth":25,"bounds":{"left":0.61136967,"top":0.89944136,"width":0.022273935,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It is really impressive how much effort he has made to always know at least a few sentences in the language corresponding to the country he has visited. The words always sound clear, and his voice is absolutely unmistakable anyway. :)","depth":24,"bounds":{"left":0.59142286,"top":0.91660017,"width":0.2606383,"height":0.029130088},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Označiť, že sa vám tento komentár páči, tak ako 119 ďalším ľuďom","depth":24,"bounds":{"left":0.5887633,"top":0.9505187,"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":"119","depth":24,"bounds":{"left":0.5994016,"top":0.95730245,"width":0.0068151597,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Tento komentár sa mi nepáči","depth":24,"bounds":{"left":0.60887635,"top":0.9505187,"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":"Odpovedať","depth":24,"bounds":{"left":0.6221742,"top":0.9505187,"width":0.027260639,"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":"Odpovedať","depth":27,"bounds":{"left":0.62616354,"top":0.95730245,"width":0.019281914,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Ponuka akcií","depth":22,"bounds":{"left":0.8424202,"top":0.8882682,"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},{"role":"AXButton","text":"1 odpoveď","depth":22,"bounds":{"left":0.58610374,"top":0.9856345,"width":0.04055851,"height":0.014365494},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1 odpoveď","depth":25,"bounds":{"left":0.59142286,"top":0.9932163,"width":0.021941489,"height":0.006783724},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"@Chavezoid","depth":21,"bounds":{"left":0.57413566,"top":1.0,"width":0.011968086,"height":-0.027134895},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"@Chavezoid","depth":23,"bounds":{"left":0.59142286,"top":1.0,"width":0.025265958,"height":-0.027134895},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"@Chavezoid","depth":24,"bounds":{"left":0.59142286,"top":1.0,"width":0.023936171,"height":-0.027134895},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"@Chavezoid","depth":25,"bounds":{"left":0.59142286,"top":1.0,"width":0.023936171,"height":-0.027933002},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"pred 6 rokmi","depth":24,"bounds":{"left":0.61668885,"top":1.0,"width":0.022273935,"height":-0.027134895},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"pred 6 rokmi","depth":25,"bounds":{"left":0.61668885,"top":1.0,"width":0.022273935,"height":-0.028730989},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Wow, his Polish is flawless, even sounds native.","depth":24,"bounds":{"left":0.59142286,"top":1.0,"width":0.09790558,"height":-0.045889854},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Označiť, že sa vám tento komentár páči, tak ako 807 ďalším ľuďom","depth":24,"bounds":{"left":0.5887633,"top":1.0,"width":0.010638298,"height":-0.06384683},"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"807","depth":24,"bounds":{"left":0.5994016,"top":1.0,"width":0.0068151597,"height":-0.07063043},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Tento komentár sa mi nepáči","depth":24,"bounds":{"left":0.60887635,"top":1.0,"width":0.010638298,"height":-0.06384683},"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Odpovedať","depth":24,"bounds":{"left":0.6221742,"top":1.0,"width":0.027260639,"height":-0.06384683},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Odpovedať","depth":27,"bounds":{"left":0.62616354,"top":1.0,"width":0.019281914,"height":-0.07063043},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Ponuka akcií","depth":22,"bounds":{"left":0.8424202,"top":1.0,"width":0.013297873,"height":-0.01755786},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"65 odpovedí","depth":22,"bounds":{"left":0.58610374,"top":1.0,"width":0.044215426,"height":-0.098962545},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"65 odpovedí","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"@diegoboatman3196","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"@diegoboatman3196","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"@diegoboatman3196","depth":24,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"@diegoboatman3196","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"pred 5 rokmi","depth":24,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"pred 5 rokmi","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Juan Pablo II ha sido el más grande de todos los papas, logró unir al mundo.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Preložiť do jazyka angličtina","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Označiť, že sa vám tento komentár páči, tak ako 32 ďalším ľuďom","depth":24,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"32","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Tento komentár sa mi nepáči","depth":24,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Odpovedať","depth":24,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Odpovedať","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Ponuka akcií","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"@luistorresalcantara5270","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"@luistorresalcantara5270","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"@luistorresalcantara5270","depth":24,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"@luistorresalcantara5270","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"pred 5 rokmi","depth":24,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"pred 5 rokmi","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Este hombre era un sabio, es increíble.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Preložiť do jazyka angličtina","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Označiť, že sa vám tento komentár páči, tak ako 67 ďalším ľuďom","depth":24,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"67","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Tento komentár sa mi nepáči","depth":24,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Odpovedať","depth":24,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Odpovedať","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Ponuka akcií","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"@karinaflores254","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"@karinaflores254","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"@karinaflores254","depth":24,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"@karinaflores254","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"pred 5 rokmi (upravené)","depth":24,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"pred 5 rokmi (upravené)","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Yo estoy estudiando ingles y francés, ya casi llevo 2 años y no los domino. Es impresionante que este Papa haya hablado 13 idiomas y quizás más","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Preložiť do jazyka angličtina","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Označiť, že sa vám tento komentár páči, tak ako 233 ďalším ľuďom","depth":24,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"233","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Tento komentár sa mi nepáči","depth":24,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Odpovedať","depth":24,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Odpovedať","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Ponuka akcií","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"14 odpovedí","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"14 odpovedí","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"@sky_idk7","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"@sky_idk7","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"@sky_idk7","depth":24,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"@sky_idk7","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"pred 1 rokom (upravené)","depth":24,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"pred 1 rokom (upravené)","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Su español era muy muy bueno. Aunque en el vídeo, el papa ya estaba muy mayor y enfermo, cuando era más joven lo hablaba perfecto. Se nota que dominaba el idioma porque no sólo lo he escuchado decir discursos leyendo, sino que él sabía improvisar e incluso hacer bromas. Era re carismático y encantador.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Preložiť do jazyka angličtina","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Označiť, že sa vám tento komentár páči, tak ako 27 ďalším ľuďom","depth":24,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"27","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Tento komentár sa mi nepáči","depth":24,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Odpovedať","depth":24,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Odpovedať","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Ponuka akcií","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"@marcioe.7579","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"@marcioe.7579","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"@marcioe.7579","depth":24,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"@marcioe.7579","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"pred 1 rokom","depth":24,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"pred 1 rokom","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"O papa falava 16 idiomas. É impressionante como eles conseguem dominar tudo isso.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Preložiť do jazyka angličtina","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Označiť, že sa vám tento komentár páči, tak ako 6 ďalším ľuďom","depth":24,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"6","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Tento komentár sa mi nepáči","depth":24,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Odpovedať","depth":24,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Odpovedať","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Ponuka akcií","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"@owlieo.3432","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"@owlieo.3432","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"@owlieo.3432","depth":24,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"@owlieo.3432","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"pred 1 rokom","depth":24,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"pred 1 rokom","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Que homem extraordinário!","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Preložiť do jazyka angličtina","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Označiť, že sa vám tento komentár páči, tak ako 17 ďalším ľuďom","depth":24,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"17","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Tento komentár sa mi nepáči","depth":24,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Odpovedať","depth":24,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Odpovedať","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Ponuka akcií","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-8065409411627687571
|
-7928448855634542170
|
visual_change
|
accessibility
|
NULL
|
New Tab
New Tab
Screenpipe — Archive
Screenpipe — New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
All docs · AFFiNE
All docs · AFFiNE
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
(172) Papa Juan Pablo II hablando en 13 Idiomas - YouTube
Mute tab
(172) Papa Juan Pablo II hablando en 13 Idiomas - YouTube
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Sprievodca
Domovská stránka YouTube
BG
Preskočiť navigáciu
Preskočiť navigáciu
Karol Wojtyla speaking langauges
Karol Wojtyla speaking langauges
Vymazať vyhľadávací dopyt
Search
Vyhľadávať hlasom
Vytvoriť
Vytvoriť
Upozornenia
9+
Ponuka účtu
Zobraziť karty
Vodoznak kanála
Prehrávanie (k)
Stlmiť (m)
0 min 48 s z 5 min 42 s
0:48
/
5:42
Automatické prehrávanie je zapnuté
Titulky alebo skryté titulky sú nedostupné
Nastavenia
Režim kina (t)
Celá obrazovka (f)
Papa Juan Pablo II hablando en 13 Idiomas
Papa Juan Pablo II hablando en 13 Idiomas
Manoloyy
Manoloyy
124 tis. odberateľov
Prihlásiť sa na odber kanála Manoloyy.
Odoberať
Označiť, že sa mi toto video páči, tak ako 7 562 ďalším osobám
7,5 tis.
Toto video sa mi nepáči
Zdieľať
Zdieľať
Uložiť do zoznamu
Uložiť
Ďalšie akcie
350 tis. zhliadnutí
pred 8 rokmi
El Papa Juan Pablo II (Karol Wojtyla) hablando en inglés, español, alemán, portugués, francés, italiano, ruso, japonés, croata, checo, ucraniano, latín y polaco
...viac
...viac
916 komentárov
916
komentárov
Zoradiť komentáre
Zoradiť podľa
Pridajte komentár…
@danielnainggolan6258
@danielnainggolan6258
@danielnainggolan6258
@danielnainggolan6258
pred 1 rokom
pred 1 rokom
0:03
0:03
English/Inglés 🇬🇧
0:33
0:33
Spanish/idioma español 🇪🇸
1:07
1:07
German/idioma alemán 🇩🇪
1:35
1:35
Portuguese/Portugués 🇵🇹
1:55
1:55
French/Francés 🇫🇷
2:18
2:18
Italian/italiano 🇮🇹
2:52
2:52
Russian/idioma ruso 🇷🇺
3:15
3:15
Japanese/Japonés 🇯🇵
3:33
3:33
Croatian/idioma croata
4:01
4:01
Czech/Idioma checo 🇨🇿
4:34
4:34
Ukranian/Ucraniano 🇺🇦
5:00
5:00
Latin/latín 🇻🇦
5:24
5:24
Polish/polaco 🇵🇱
Zobraziť viac
Preložiť do jazyka angličtina
Označiť, že sa vám tento komentár páči, tak ako 57 ďalším ľuďom
57
Tento komentár sa mi nepáči
Odpovedať
Odpovedať
Ponuka akcií
@Flori-an
@Flori-an
@Flori-an
@Flori-an
pred 2 rokmi
pred 2 rokmi
It is really impressive how much effort he has made to always know at least a few sentences in the language corresponding to the country he has visited. The words always sound clear, and his voice is absolutely unmistakable anyway. :)
Označiť, že sa vám tento komentár páči, tak ako 119 ďalším ľuďom
119
Tento komentár sa mi nepáči
Odpovedať
Odpovedať
Ponuka akcií
1 odpoveď
1 odpoveď
@Chavezoid
@Chavezoid
@Chavezoid
@Chavezoid
pred 6 rokmi
pred 6 rokmi
Wow, his Polish is flawless, even sounds native.
Označiť, že sa vám tento komentár páči, tak ako 807 ďalším ľuďom
807
Tento komentár sa mi nepáči
Odpovedať
Odpovedať
Ponuka akcií
65 odpovedí
65 odpovedí
@diegoboatman3196
@diegoboatman3196
@diegoboatman3196
@diegoboatman3196
pred 5 rokmi
pred 5 rokmi
Juan Pablo II ha sido el más grande de todos los papas, logró unir al mundo.
Preložiť do jazyka angličtina
Označiť, že sa vám tento komentár páči, tak ako 32 ďalším ľuďom
32
Tento komentár sa mi nepáči
Odpovedať
Odpovedať
Ponuka akcií
@luistorresalcantara5270
@luistorresalcantara5270
@luistorresalcantara5270
@luistorresalcantara5270
pred 5 rokmi
pred 5 rokmi
Este hombre era un sabio, es increíble.
Preložiť do jazyka angličtina
Označiť, že sa vám tento komentár páči, tak ako 67 ďalším ľuďom
67
Tento komentár sa mi nepáči
Odpovedať
Odpovedať
Ponuka akcií
@karinaflores254
@karinaflores254
@karinaflores254
@karinaflores254
pred 5 rokmi (upravené)
pred 5 rokmi (upravené)
Yo estoy estudiando ingles y francés, ya casi llevo 2 años y no los domino. Es impresionante que este Papa haya hablado 13 idiomas y quizás más
Preložiť do jazyka angličtina
Označiť, že sa vám tento komentár páči, tak ako 233 ďalším ľuďom
233
Tento komentár sa mi nepáči
Odpovedať
Odpovedať
Ponuka akcií
14 odpovedí
14 odpovedí
@sky_idk7
@sky_idk7
@sky_idk7
@sky_idk7
pred 1 rokom (upravené)
pred 1 rokom (upravené)
Su español era muy muy bueno. Aunque en el vídeo, el papa ya estaba muy mayor y enfermo, cuando era más joven lo hablaba perfecto. Se nota que dominaba el idioma porque no sólo lo he escuchado decir discursos leyendo, sino que él sabía improvisar e incluso hacer bromas. Era re carismático y encantador.
Preložiť do jazyka angličtina
Označiť, že sa vám tento komentár páči, tak ako 27 ďalším ľuďom
27
Tento komentár sa mi nepáči
Odpovedať
Odpovedať
Ponuka akcií
@marcioe.7579
@marcioe.7579
@marcioe.7579
@marcioe.7579
pred 1 rokom
pred 1 rokom
O papa falava 16 idiomas. É impressionante como eles conseguem dominar tudo isso.
Preložiť do jazyka angličtina
Označiť, že sa vám tento komentár páči, tak ako 6 ďalším ľuďom
6
Tento komentár sa mi nepáči
Odpovedať
Odpovedať
Ponuka akcií
@owlieo.3432
@owlieo.3432
@owlieo.3432
@owlieo.3432
pred 1 rokom
pred 1 rokom
Que homem extraordinário!
Preložiť do jazyka angličtina
Označiť, že sa vám tento komentár páči, tak ako 17 ďalším ľuďom
17
Tento komentár sa mi nepáči
Odpovedať
Odpovedať
Ponuka akcií...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
8348
|
367
|
15
|
2026-05-08T10:22:53.856717+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778235773856_m1.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Show Replace Field
Search History
rateLimiter
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
1/4
Previous Occurrence
Next Occurrence
Filter Search Results
Open in Window, Multiple Cursors
Click to highlight
Close
Sync Changes
Hide This Notification
Code changed:
Hide
2
69
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
//use Jiminny\Component\Utility\Service\ProviderRateLimiter;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
public function isHubspotRateLimit(Throwable $e): bool
{
return method_exists($e, 'getCode') && (int) $e->getCode() === 429;
}
public function parseRetryAfter(Throwable $e): int
{
// First try to get Retry-After from response headers
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
// For search APIs, headers are often missing - check response body for policyName
if (method_exists($e, 'getResponseBody')) {
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
$policyName = $body['policyName'] ?? $body['policy'] ?? null;
// Map policy names to retry delays
if ($policyName === 'TEN_SECONDLY_ROLLING' || $policyName === 'ten_secondly_rolling') {
return 10;
}
if ($policyName === 'SECONDLY' || $policyName === 'secondly') {
return 1;
}
}
// Also check nested context object if present
if (method_exists($e, 'getResponseBody')) {
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
$context = $body['context'] ?? [];
$policyName = $context['policyName'] ?? null;
if ($policyName === 'TEN_SECONDLY_ROLLING' || $policyName === 'ten_secondly_rolling') {
return 10;
}
if ($policyName === 'SECONDLY' || $policyName === 'secondly') {
return 1;
}
}
$this->log->debug('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
$response = $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
$response = $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
$max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // "110"
$remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // "109"
$interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // "10000"
$body = json_decode((string) $response->getBody(), true);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));
return $response;
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
37
1
35
64
Previous Highlighted Error...
|
[{"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":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","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":"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":"rateLimiter","depth":4,"on_screen":true,"value":"rateLimiter","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/4","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":"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":"2","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"69","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","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\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\n//use Jiminny\\Component\\Utility\\Service\\ProviderRateLimiter;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n// private ProviderRateLimiter $rateLimiter;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager,\n// ProviderRateLimiter $rateLimiter,\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n// $this->rateLimiter = $rateLimiter;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Single entry point for every HubSpot API call. Enforces the per-portal\n * rate limit configured in the rate_limits table (morphed to the current\n * Configuration) and reacts to a real 429 from HubSpot by translating it\n * into a RateLimitException carrying Retry-After.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n return method_exists($e, 'getCode') && (int) $e->getCode() === 429;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n // First try to get Retry-After from response headers\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n // For search APIs, headers are often missing - check response body for policyName\n if (method_exists($e, 'getResponseBody')) {\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n $policyName = $body['policyName'] ?? $body['policy'] ?? null;\n\n // Map policy names to retry delays\n if ($policyName === 'TEN_SECONDLY_ROLLING' || $policyName === 'ten_secondly_rolling') {\n return 10;\n }\n if ($policyName === 'SECONDLY' || $policyName === 'secondly') {\n return 1;\n }\n }\n\n // Also check nested context object if present\n if (method_exists($e, 'getResponseBody')) {\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n $context = $body['context'] ?? [];\n $policyName = $context['policyName'] ?? null;\n\n if ($policyName === 'TEN_SECONDLY_ROLLING' || $policyName === 'ten_secondly_rolling') {\n return 10;\n }\n if ($policyName === 'SECONDLY' || $policyName === 'secondly') {\n return 1;\n }\n }\n\n $this->log->debug('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n $response = $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n $response = $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n\n $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // \"110\"\n $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // \"109\"\n $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // \"10000\"\n $body = json_decode((string) $response->getBody(), true);\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));\n\n return $response;\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\n//use Jiminny\\Component\\Utility\\Service\\ProviderRateLimiter;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n// private ProviderRateLimiter $rateLimiter;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager,\n// ProviderRateLimiter $rateLimiter,\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n// $this->rateLimiter = $rateLimiter;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Single entry point for every HubSpot API call. Enforces the per-portal\n * rate limit configured in the rate_limits table (morphed to the current\n * Configuration) and reacts to a real 429 from HubSpot by translating it\n * into a RateLimitException carrying Retry-After.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n return method_exists($e, 'getCode') && (int) $e->getCode() === 429;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n // First try to get Retry-After from response headers\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n // For search APIs, headers are often missing - check response body for policyName\n if (method_exists($e, 'getResponseBody')) {\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n $policyName = $body['policyName'] ?? $body['policy'] ?? null;\n\n // Map policy names to retry delays\n if ($policyName === 'TEN_SECONDLY_ROLLING' || $policyName === 'ten_secondly_rolling') {\n return 10;\n }\n if ($policyName === 'SECONDLY' || $policyName === 'secondly') {\n return 1;\n }\n }\n\n // Also check nested context object if present\n if (method_exists($e, 'getResponseBody')) {\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n $context = $body['context'] ?? [];\n $policyName = $context['policyName'] ?? null;\n\n if ($policyName === 'TEN_SECONDLY_ROLLING' || $policyName === 'ten_secondly_rolling') {\n return 10;\n }\n if ($policyName === 'SECONDLY' || $policyName === 'secondly') {\n return 1;\n }\n }\n\n $this->log->debug('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n $response = $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n $response = $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n\n $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // \"110\"\n $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // \"109\"\n $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // \"10000\"\n $body = json_decode((string) $response->getBody(), true);\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));\n\n return $response;\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"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":"37","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"35","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"64","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}]...
|
-8064121503012831394
|
-3997534158179133340
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Show Replace Field
Search History
rateLimiter
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
1/4
Previous Occurrence
Next Occurrence
Filter Search Results
Open in Window, Multiple Cursors
Click to highlight
Close
Sync Changes
Hide This Notification
Code changed:
Hide
2
69
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
//use Jiminny\Component\Utility\Service\ProviderRateLimiter;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
public function isHubspotRateLimit(Throwable $e): bool
{
return method_exists($e, 'getCode') && (int) $e->getCode() === 429;
}
public function parseRetryAfter(Throwable $e): int
{
// First try to get Retry-After from response headers
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
// For search APIs, headers are often missing - check response body for policyName
if (method_exists($e, 'getResponseBody')) {
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
$policyName = $body['policyName'] ?? $body['policy'] ?? null;
// Map policy names to retry delays
if ($policyName === 'TEN_SECONDLY_ROLLING' || $policyName === 'ten_secondly_rolling') {
return 10;
}
if ($policyName === 'SECONDLY' || $policyName === 'secondly') {
return 1;
}
}
// Also check nested context object if present
if (method_exists($e, 'getResponseBody')) {
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
$context = $body['context'] ?? [];
$policyName = $context['policyName'] ?? null;
if ($policyName === 'TEN_SECONDLY_ROLLING' || $policyName === 'ten_secondly_rolling') {
return 10;
}
if ($policyName === 'SECONDLY' || $policyName === 'secondly') {
return 1;
}
}
$this->log->debug('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
$response = $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
$response = $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
$max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // "110"
$remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // "109"
$interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // "10000"
$body = json_decode((string) $response->getBody(), true);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));
return $response;
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
37
1
35
64
Previous Highlighted Error...
|
8347
|
NULL
|
NULL
|
NULL
|
|
256
|
12
|
23
|
2026-05-07T06:50:33.326889+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778136633326_m2.jpg...
|
Firefox
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira — Work...
|
True
|
jiminny.atlassian.net/jira/software/c/projects/JY/ jiminny.atlassian.net/jira/software/c/projects/JY/boards/37?selectedIssue=JY-20725...
|
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
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Sentry
Sentry
Pull requests · jiminny/app
Pull requests · jiminny/app
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Space navigation
Space navigation
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent
Starred
Starred
Apps
Apps
More actions for Apps
More actions for Apps
Spaces
Spaces
Create space
Create space
More actions for spaces
More actions for spaces
Recent
Jiminny (New)
Jiminny (New)
Jiminny (New)
Create board
Create board
More actions for Jiminny (New)
More actions for Jiminny (New)
Platform Team
Platform Team
Board actions
Board actions
Capture Team
Capture Team
Board actions
Board actions
Enterprise Stability Issues 🤕
Enterprise Stability Issues 🤕
Board actions
Board actions
Processing Team
Processing Team
Board actions
Board actions
SE Kanban
SE Kanban
Board actions
Board actions
Service-Desk
Service-Desk
More actions for Service-Desk
More actions for Service-Desk
Queues
Queues
Create
Create
More for queues
More for queues
Service requests
Service requests
Create
Create
More for service requests
More for service requests
Incidents
Incidents
Create
Create
More for incidents
More for incidents
Reports
Reports
More actions for reports
More actions for reports
Operations
Operations
More actions for operations
More actions for operations
Knowledge Base
Knowledge Base
More actions for knowledge base
More actions for knowledge base
Customers
Customers
More actions for customers
More actions for customers
Channels
Channels
Email logs
Email logs
More actions for customer notification logs
More actions for customer notification logs
Developer escalations
Developer escalations
More actions for developer escalations
More actions for developer escalations
Slack integration
Slack integration
More actions for Slack integration
More actions for Slack integration
Reporting Center
Reporting Center
More actions for Reporting Center
More actions for Reporting Center
Add shortcut
Add shortcut
More actions for developer escalations
More actions for developer escalations
Archived work items
Archived work items
More actions for archived work items
More actions for archived work items
More spaces
More spaces
Filters
Filters
More actions for Filters
More actions for Filters
Dashboards
Dashboards
Create dashboard
Create dashboard
More actions for Dashboards
More actions for Dashboards
Operations
Operations
More actions for Operations
More actions for Operations
Confluence , (opens new window)
Confluence
, (opens new window)
Teams , (opens new window)
Teams
, (opens new window)
open menu
open menu
Customise sidebar
Customise sidebar
Resize side navigation panel
Spaces
Spaces
/
Jiminny (New)
Jiminny (New)
Platform Team
Platform Team
Add people
Add people
Board actions
Board actions
Share
Automation
Give feedback
Give feedback
Enter full screen
Enter full screen
Summary
Summary
Timeline
Timeline
Backlog
Backlog
Active sprints
Active sprints
Calendar
Calendar
Reports
Reports
Testing Board
Testing Board
List
List
Forms
Forms
Components
Components
Development
Development
Code
Code
Security
Security
Releases
Releases
Deployments
Deployments
5 more tabs
More
5
Add to navigation
As you type to search or apply filters, the board updates with work items to match.
Search on current page
Filter by assignee
Filter assignees by Lukas Kovalik
Filter assignees by Aneliya Angelova
Filter assignees by Nikolay Ivanov
Filter assignees by Nikolay Nikolov
Filter assignees by Steliyan Georgiev
Filter assignees by Unassigned
Epic
Epic
Type
Type
Quick filters
Quick filters
Complete sprint
Complete sprint
Sprint details
Sprint details
Group by Queries
Group
: Queries
Sprint insights
Sprint insights
View settings
View settings
More actions
More actions
Ready For DEV
READY FOR DEV
3
JY-20361 AJ Panorama for Call Scoring in OD. Use the enter key to load the work item.
AJ Panorama for Call Scoring in OD
AUTOMATED AI SCORING
Backlog
JY-20361
JY-20361
2.5
JY-20725 [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts. Use the enter key to load the work item.
[HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts
Platform Stability, Edit Parent
PLATFORM STABILITY
Backlog
JY-20725
JY-20725
4
Assignee: Lukas Kovalik
JY-19951 Setup test coverage for Prophet in Sonar. Use the enter key to load the work item.
Setup test coverage for Prophet in Sonar
Maintenance, Edit Parent
MAINTENANCE
Backlog
JY-19951
JY-19951
1
In DEV
IN DEV
2
JY-20566 AI Review - Q1 - Summary/Action items/Key Points. Use the enter key to load the work item.
AI Review - Q1 - Summary/Action items/Key Points...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.22240691,"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":true},{"role":"AXStaticText","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.2357048,"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.2897274,"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":"Service-Desk - Queues - Platform team - Service space - Jira","depth":4,"bounds":{"left":0.22240691,"top":0.08459697,"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.2357048,"top":0.09577015,"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.22240691,"top":0.11731844,"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.2357048,"top":0.12849163,"width":0.17037898,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Sentry","depth":4,"bounds":{"left":0.22240691,"top":0.15003991,"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":"Sentry","depth":5,"bounds":{"left":0.2357048,"top":0.16121309,"width":0.011303191,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pull requests · jiminny/app","depth":4,"bounds":{"left":0.22240691,"top":0.18276137,"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":"Pull requests · jiminny/app","depth":5,"bounds":{"left":0.2357048,"top":0.19393456,"width":0.04537899,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.2252327,"top":0.21707901,"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.2252327,"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.23620346,"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.24734043,"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.2584774,"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.26961437,"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":"Skip to:","depth":9,"bounds":{"left":0.31266624,"top":0.07861133,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Top Bar","depth":10,"bounds":{"left":0.31266624,"top":0.097765364,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Top Bar","depth":11,"bounds":{"left":0.31266624,"top":0.097765364,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sidebar","depth":10,"bounds":{"left":0.31266624,"top":0.11691939,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sidebar","depth":11,"bounds":{"left":0.31266624,"top":0.11691939,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Main Content","depth":10,"bounds":{"left":0.31266624,"top":0.13607343,"width":0.029421542,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Main Content","depth":11,"bounds":{"left":0.31266624,"top":0.13607343,"width":0.029421542,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Space navigation","depth":10,"bounds":{"left":0.31266624,"top":0.15522745,"width":0.037898935,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Space navigation","depth":11,"bounds":{"left":0.31266624,"top":0.15522745,"width":0.037898935,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse sidebar [","depth":9,"bounds":{"left":0.30601728,"top":0.057861134,"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":"Collapse sidebar [","depth":11,"bounds":{"left":0.31117022,"top":0.06344773,"width":0.039727394,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Switch sites or apps","depth":10,"bounds":{"left":0.3179854,"top":0.057861134,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Switch sites or apps","depth":12,"bounds":{"left":0.3231383,"top":0.06344773,"width":0.044215426,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Go to your Jira homepage","depth":9,"bounds":{"left":0.33128324,"top":0.057861134,"width":0.029421542,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"Search, press enter to navigate to advanced search with your text query","depth":10,"bounds":{"left":0.5159575,"top":0.06264964,"width":0.24268617,"height":0.015961692},"on_screen":true,"help_text":"","placeholder":"Search","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Create","depth":10,"bounds":{"left":0.7669548,"top":0.057861134,"width":0.030086435,"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":"Create","depth":12,"bounds":{"left":0.77825797,"top":0.06384677,"width":0.014793883,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Rovo Ask Rovo","depth":12,"bounds":{"left":0.91223407,"top":0.057861134,"width":0.035904255,"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 Rovo","depth":14,"bounds":{"left":0.92353725,"top":0.06384677,"width":0.020611702,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Notifications","depth":12,"bounds":{"left":0.9494681,"top":0.057861134,"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":"Notifications","depth":14,"bounds":{"left":0.954621,"top":0.06344773,"width":0.027759308,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Help","depth":12,"bounds":{"left":0.96143615,"top":0.057861134,"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":"Help","depth":14,"bounds":{"left":0.9665891,"top":0.06344773,"width":0.010139627,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Settings","depth":12,"bounds":{"left":0.9734042,"top":0.057861134,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Settings","depth":14,"bounds":{"left":0.97855717,"top":0.06344773,"width":0.017952127,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.98537236,"top":0.057861134,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"lukas.kovalik@jiminny.com","depth":14,"bounds":{"left":0.99052525,"top":0.06344773,"width":0.009474754,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"For you","depth":12,"bounds":{"left":0.30601728,"top":0.09976058,"width":0.071476065,"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":"For you","depth":15,"bounds":{"left":0.31665558,"top":0.10574621,"width":0.01662234,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Recent","depth":12,"bounds":{"left":0.30601728,"top":0.12529927,"width":0.071476065,"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":"Recent","depth":15,"bounds":{"left":0.31665558,"top":0.13128492,"width":0.015458777,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Starred","depth":12,"bounds":{"left":0.30601728,"top":0.15083799,"width":0.071476065,"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":"Starred","depth":15,"bounds":{"left":0.31665558,"top":0.15682362,"width":0.016456118,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Apps","depth":12,"bounds":{"left":0.30601728,"top":0.1763767,"width":0.071476065,"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":"Apps","depth":15,"bounds":{"left":0.31665558,"top":0.18236233,"width":0.011635638,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Apps","depth":13,"bounds":{"left":0.37549868,"top":0.17956904,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Apps","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Spaces","depth":12,"bounds":{"left":0.30601728,"top":0.2019154,"width":0.071476065,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Spaces","depth":15,"bounds":{"left":0.31665558,"top":0.20790103,"width":0.016456118,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create space","depth":13,"bounds":{"left":0.35887632,"top":0.20510775,"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":"AXStaticText","text":"Create space","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for spaces","depth":13,"bounds":{"left":0.36818483,"top":0.20510775,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for spaces","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Recent","depth":16,"bounds":{"left":0.31200132,"top":0.23423783,"width":0.013464096,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny (New)","depth":17,"bounds":{"left":0.31000665,"top":0.2529928,"width":0.0674867,"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":"Jiminny (New)","depth":20,"bounds":{"left":0.32064494,"top":0.25897846,"width":0.032081116,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Jiminny (New)","depth":18,"bounds":{"left":0.31133643,"top":0.25618514,"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,"is_expanded":true},{"role":"AXMenuButton","text":"Create board","depth":18,"bounds":{"left":0.35887632,"top":0.25618514,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Create board","depth":20,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Jiminny (New)","depth":18,"bounds":{"left":0.36818483,"top":0.25618514,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Jiminny (New)","depth":20,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Platform Team","depth":19,"bounds":{"left":0.31399602,"top":0.27853152,"width":0.06349734,"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":"Platform Team","depth":22,"bounds":{"left":0.3246343,"top":0.28451717,"width":0.032247342,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"bounds":{"left":0.37549868,"top":0.28172386,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Capture Team","depth":19,"bounds":{"left":0.31399602,"top":0.30407023,"width":0.06349734,"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":"Capture Team","depth":22,"bounds":{"left":0.3246343,"top":0.31005585,"width":0.03125,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"bounds":{"left":0.37549868,"top":0.30726257,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Enterprise Stability Issues 🤕","depth":19,"bounds":{"left":0.31399602,"top":0.32960895,"width":0.06349734,"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":"Enterprise Stability Issues 🤕","depth":22,"bounds":{"left":0.3246343,"top":0.33559456,"width":0.050531916,"height":0.030726258},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"bounds":{"left":0.37549868,"top":0.33280128,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Processing Team","depth":19,"bounds":{"left":0.31399602,"top":0.35514766,"width":0.06349734,"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":"Processing Team","depth":22,"bounds":{"left":0.3246343,"top":0.36113328,"width":0.038231384,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"bounds":{"left":0.37549868,"top":0.35834,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SE Kanban","depth":19,"bounds":{"left":0.31399602,"top":0.38068634,"width":0.06349734,"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":"SE Kanban","depth":22,"bounds":{"left":0.3246343,"top":0.386672,"width":0.024102394,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"bounds":{"left":0.37549868,"top":0.38387868,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Service-Desk","depth":17,"bounds":{"left":0.31000665,"top":0.40622506,"width":0.0674867,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Service-Desk","depth":20,"bounds":{"left":0.32064494,"top":0.4122107,"width":0.03025266,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Service-Desk","depth":18,"bounds":{"left":0.36818483,"top":0.4094174,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Service-Desk","depth":20,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Queues","depth":21,"bounds":{"left":0.31399602,"top":0.43176377,"width":0.06349734,"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":"Queues","depth":24,"bounds":{"left":0.3246343,"top":0.43774942,"width":0.017121011,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Create","depth":22,"bounds":{"left":0.37549868,"top":0.4349561,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Create","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More for queues","depth":22,"bounds":{"left":0.37682846,"top":0.4349561,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More for queues","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Service requests","depth":21,"bounds":{"left":0.31399602,"top":0.45730248,"width":0.06349734,"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":"Service requests","depth":24,"bounds":{"left":0.3246343,"top":0.4632881,"width":0.03756649,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Create","depth":22,"bounds":{"left":0.37549868,"top":0.46049482,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Create","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More for service requests","depth":22,"bounds":{"left":0.37682846,"top":0.46049482,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More for service requests","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Incidents","depth":22,"bounds":{"left":0.31399602,"top":0.4828412,"width":0.06349734,"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":"Incidents","depth":25,"bounds":{"left":0.3246343,"top":0.4888268,"width":0.021276595,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Create","depth":23,"bounds":{"left":0.37549868,"top":0.48603353,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Create","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More for incidents","depth":23,"bounds":{"left":0.37682846,"top":0.48603353,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More for incidents","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Reports","depth":19,"bounds":{"left":0.31399602,"top":0.5083799,"width":0.06349734,"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":"Reports","depth":22,"bounds":{"left":0.3246343,"top":0.5143655,"width":0.017287234,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for reports","depth":20,"bounds":{"left":0.37549868,"top":0.51157224,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for reports","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Operations","depth":19,"bounds":{"left":0.31399602,"top":0.5339186,"width":0.06349734,"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":"Operations","depth":22,"bounds":{"left":0.3246343,"top":0.53990424,"width":0.02443484,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for operations","depth":20,"bounds":{"left":0.37549868,"top":0.5371109,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for operations","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Knowledge Base","depth":19,"bounds":{"left":0.31399602,"top":0.5594573,"width":0.06349734,"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":"Knowledge Base","depth":22,"bounds":{"left":0.3246343,"top":0.5654429,"width":0.03723404,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for knowledge base","depth":20,"bounds":{"left":0.37549868,"top":0.56264967,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for knowledge base","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Customers","depth":19,"bounds":{"left":0.31399602,"top":0.584996,"width":0.06349734,"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":"Customers","depth":22,"bounds":{"left":0.3246343,"top":0.59098166,"width":0.024268618,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for customers","depth":20,"bounds":{"left":0.37549868,"top":0.58818835,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for customers","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Channels","depth":19,"bounds":{"left":0.31399602,"top":0.6105347,"width":0.06349734,"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":"Channels","depth":22,"bounds":{"left":0.3246343,"top":0.61652035,"width":0.020944148,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Email logs","depth":19,"bounds":{"left":0.31399602,"top":0.6360734,"width":0.06349734,"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":"Email logs","depth":22,"bounds":{"left":0.3246343,"top":0.6420591,"width":0.022606382,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for customer notification logs","depth":20,"bounds":{"left":0.37549868,"top":0.6392658,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for customer notification logs","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Developer escalations","depth":19,"bounds":{"left":0.31399602,"top":0.66161215,"width":0.06349734,"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":"Developer escalations","depth":22,"bounds":{"left":0.3246343,"top":0.6675978,"width":0.04920213,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for developer escalations","depth":20,"bounds":{"left":0.37549868,"top":0.66480446,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for developer escalations","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Slack integration","depth":19,"bounds":{"left":0.31399602,"top":0.68715084,"width":0.06349734,"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":"Slack integration","depth":22,"bounds":{"left":0.3246343,"top":0.69313645,"width":0.03723404,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Slack integration","depth":20,"bounds":{"left":0.37549868,"top":0.6903432,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Slack integration","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Reporting Center","depth":19,"bounds":{"left":0.31399602,"top":0.7126895,"width":0.06349734,"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":"Reporting Center","depth":22,"bounds":{"left":0.3246343,"top":0.7186752,"width":0.037898935,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Reporting Center","depth":20,"bounds":{"left":0.37549868,"top":0.7158819,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Reporting Center","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Add shortcut","depth":19,"bounds":{"left":0.31399602,"top":0.73822826,"width":0.06349734,"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":"Add shortcut","depth":22,"bounds":{"left":0.3246343,"top":0.7442139,"width":0.028922873,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for developer escalations","depth":20,"bounds":{"left":0.37549868,"top":0.74142057,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for developer escalations","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Archived work items","depth":19,"bounds":{"left":0.31399602,"top":0.76376694,"width":0.06349734,"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":"Archived work items","depth":22,"bounds":{"left":0.3246343,"top":0.7697526,"width":0.045545213,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for archived work items","depth":20,"bounds":{"left":0.37549868,"top":0.7669593,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for archived work items","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"More spaces","depth":17,"bounds":{"left":0.31000665,"top":0.7893057,"width":0.0674867,"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":"More spaces","depth":20,"bounds":{"left":0.32064494,"top":0.7952913,"width":0.028756648,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Filters","depth":12,"bounds":{"left":0.30601728,"top":0.81484437,"width":0.071476065,"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":"Filters","depth":15,"bounds":{"left":0.31665558,"top":0.82083,"width":0.013796543,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Filters","depth":13,"bounds":{"left":0.37549868,"top":0.81803674,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Filters","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dashboards","depth":12,"bounds":{"left":0.30601728,"top":0.84038305,"width":0.071476065,"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":"Dashboards","depth":15,"bounds":{"left":0.31665558,"top":0.84636873,"width":0.026761968,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create dashboard","depth":13,"bounds":{"left":0.37749335,"top":0.8435754,"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":"AXStaticText","text":"Create dashboard","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Dashboards","depth":13,"bounds":{"left":0.38480717,"top":0.8435754,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Dashboards","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Operations","depth":12,"bounds":{"left":0.30601728,"top":0.8659218,"width":0.071476065,"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":"Operations","depth":15,"bounds":{"left":0.31665558,"top":0.8719074,"width":0.02443484,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Operations","depth":13,"bounds":{"left":0.37549868,"top":0.8691141,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Operations","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Confluence , (opens new window)","depth":13,"bounds":{"left":0.30601728,"top":0.9010375,"width":0.071476065,"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":"Confluence","depth":17,"bounds":{"left":0.31665558,"top":0.90702313,"width":0.025764627,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", (opens new window)","depth":15,"bounds":{"left":0.30601728,"top":0.91460496,"width":0.04837101,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Teams , (opens new window)","depth":13,"bounds":{"left":0.30601728,"top":0.9265762,"width":0.071476065,"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":"Teams","depth":17,"bounds":{"left":0.31665558,"top":0.9325619,"width":0.014793883,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", (opens new window)","depth":15,"bounds":{"left":0.30601728,"top":0.94014364,"width":0.04837101,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"open menu","depth":14,"bounds":{"left":0.36619017,"top":0.92976856,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"open menu","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Customise sidebar","depth":12,"bounds":{"left":0.30601728,"top":0.9616919,"width":0.071476065,"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":"Customise sidebar","depth":15,"bounds":{"left":0.31665558,"top":0.9676776,"width":0.04155585,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Resize side navigation panel","depth":13,"bounds":{"left":0.43334442,"top":0.0981644,"width":0.062333778,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Spaces","depth":13,"bounds":{"left":0.38979387,"top":0.09976058,"width":0.016289894,"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":"Spaces","depth":15,"bounds":{"left":0.38979387,"top":0.102553874,"width":0.016289894,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":13,"bounds":{"left":0.40924203,"top":0.102553874,"width":0.0016622341,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny (New)","depth":13,"bounds":{"left":0.4140625,"top":0.09976058,"width":0.03174867,"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":"Jiminny (New)","depth":15,"bounds":{"left":0.4140625,"top":0.102553874,"width":0.03174867,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Platform Team","depth":10,"bounds":{"left":0.38979387,"top":0.12210695,"width":0.045877658,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Platform Team","depth":11,"bounds":{"left":0.38979387,"top":0.12210695,"width":0.045877658,"height":0.019553073},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Add people","depth":10,"bounds":{"left":0.43766624,"top":0.118914604,"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":"Add people","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":10,"bounds":{"left":0.4502992,"top":0.118914604,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Share","depth":10,"bounds":{"left":0.94148934,"top":0.118914604,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Automation","depth":10,"bounds":{"left":0.95478725,"top":0.118914604,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Give feedback","depth":10,"bounds":{"left":0.9680851,"top":0.118914604,"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":"Give feedback","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Enter full screen","depth":10,"bounds":{"left":0.98138297,"top":0.118914604,"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":"Enter full screen","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Summary","depth":13,"bounds":{"left":0.3871343,"top":0.14764565,"width":0.035904255,"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":"Summary","depth":15,"bounds":{"left":0.3984375,"top":0.15363128,"width":0.021276595,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Timeline","depth":13,"bounds":{"left":0.42436835,"top":0.14764565,"width":0.03357713,"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":"Timeline","depth":15,"bounds":{"left":0.43567154,"top":0.15363128,"width":0.018949468,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Backlog","depth":13,"bounds":{"left":0.45927528,"top":0.14764565,"width":0.032413565,"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":"Backlog","depth":15,"bounds":{"left":0.47057846,"top":0.15363128,"width":0.017785905,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Active sprints","depth":13,"bounds":{"left":0.49301863,"top":0.14764565,"width":0.045212764,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Active sprints","depth":15,"bounds":{"left":0.5043218,"top":0.15363128,"width":0.030585106,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Calendar","depth":13,"bounds":{"left":0.53956115,"top":0.14764565,"width":0.03474069,"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":"Calendar","depth":15,"bounds":{"left":0.55086434,"top":0.15363128,"width":0.020113032,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Reports","depth":13,"bounds":{"left":0.5756317,"top":0.14764565,"width":0.031914894,"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":"Reports","depth":15,"bounds":{"left":0.58693486,"top":0.15363128,"width":0.017287234,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Testing Board","depth":13,"bounds":{"left":0.60887635,"top":0.14764565,"width":0.046708778,"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":"Testing Board","depth":15,"bounds":{"left":0.62017953,"top":0.15363128,"width":0.030751329,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"List","depth":13,"bounds":{"left":0.6569149,"top":0.14764565,"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":"List","depth":15,"bounds":{"left":0.6682181,"top":0.15363128,"width":0.0078125,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Forms","depth":13,"bounds":{"left":0.68068486,"top":0.14764565,"width":0.028590426,"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":"Forms","depth":15,"bounds":{"left":0.69198805,"top":0.15363128,"width":0.013962766,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Components","depth":13,"bounds":{"left":0.710605,"top":0.14764565,"width":0.04305186,"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":"Components","depth":15,"bounds":{"left":0.7219083,"top":0.15363128,"width":0.028424202,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Development","depth":13,"bounds":{"left":0.7549867,"top":0.14764565,"width":0.044049203,"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":"Development","depth":15,"bounds":{"left":0.7662899,"top":0.15363128,"width":0.029421542,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":13,"bounds":{"left":0.8003657,"top":0.14764565,"width":0.02642952,"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":"Code","depth":15,"bounds":{"left":0.8116689,"top":0.15363128,"width":0.011801862,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security","depth":13,"bounds":{"left":0.828125,"top":0.14764565,"width":0.03324468,"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":"Security","depth":15,"bounds":{"left":0.8394282,"top":0.15363128,"width":0.01861702,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Releases","depth":13,"bounds":{"left":0.86269945,"top":0.14764565,"width":0.034574468,"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":"Releases","depth":15,"bounds":{"left":0.87400264,"top":0.15363128,"width":0.019946808,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Deployments","depth":13,"bounds":{"left":0.89860374,"top":0.14764565,"width":0.043882977,"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":"Deployments","depth":15,"bounds":{"left":0.9099069,"top":0.15363128,"width":0.02925532,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"5 more tabs","depth":11,"bounds":{"left":0.9438165,"top":0.14764565,"width":0.026097074,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":12,"bounds":{"left":0.94714093,"top":0.15363128,"width":0.011469414,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5","depth":13,"bounds":{"left":0.96276593,"top":0.15442938,"width":0.0023271276,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Add to navigation","depth":11,"bounds":{"left":0.9712433,"top":0.15083799,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"As you type to search or apply filters, the board updates with work items to match.","depth":11,"bounds":{"left":0.38979387,"top":0.20271349,"width":0.18134974,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Search on current page","depth":11,"bounds":{"left":0.39810506,"top":0.188747,"width":0.050531916,"height":0.026735835},"on_screen":true,"placeholder":"Search board","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Filter by assignee","depth":12,"bounds":{"left":0.45362368,"top":0.19034317,"width":0.03873005,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Filter assignees by Lukas Kovalik","depth":11,"bounds":{"left":0.45495346,"top":0.18914606,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Filter assignees by Aneliya Angelova","depth":11,"bounds":{"left":0.46293217,"top":0.18914606,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Filter assignees by Nikolay Ivanov","depth":11,"bounds":{"left":0.4709109,"top":0.18914606,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Filter assignees by Nikolay Nikolov","depth":11,"bounds":{"left":0.4788896,"top":0.18914606,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Filter assignees by Steliyan Georgiev","depth":11,"bounds":{"left":0.48686835,"top":0.18914606,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Filter assignees by Unassigned","depth":11,"bounds":{"left":0.4948471,"top":0.18914606,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Epic","depth":13,"bounds":{"left":0.50681514,"top":0.18914606,"width":0.0234375,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Epic","depth":16,"bounds":{"left":0.51080453,"top":0.19513169,"width":0.009474734,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Type","depth":13,"bounds":{"left":0.53291225,"top":0.18914606,"width":0.025099734,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Type","depth":16,"bounds":{"left":0.5369016,"top":0.19513169,"width":0.011136968,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Quick filters","depth":13,"bounds":{"left":0.56067157,"top":0.18914606,"width":0.040724736,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Quick filters","depth":16,"bounds":{"left":0.5646609,"top":0.19513169,"width":0.026761968,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Complete sprint","depth":10,"bounds":{"left":0.85106385,"top":0.18914606,"width":0.04338431,"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":"Complete sprint","depth":12,"bounds":{"left":0.8550532,"top":0.19513169,"width":0.035405584,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Sprint details","depth":10,"bounds":{"left":0.8971077,"top":0.18914606,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Sprint details","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Group by Queries","depth":10,"bounds":{"left":0.9104056,"top":0.18914606,"width":0.041722074,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Group","depth":13,"bounds":{"left":0.914395,"top":0.19513169,"width":0.013796543,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":": Queries","depth":13,"bounds":{"left":0.9281915,"top":0.19513169,"width":0.019946808,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Sprint insights","depth":10,"bounds":{"left":0.95478725,"top":0.18914606,"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":"Sprint insights","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"View settings","depth":10,"bounds":{"left":0.9680851,"top":0.18914606,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"View settings","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions","depth":10,"bounds":{"left":0.98138297,"top":0.18914606,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Ready For DEV","depth":16,"bounds":{"left":0.39245346,"top":0.24022347,"width":0.042220745,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"READY FOR DEV","depth":18,"bounds":{"left":0.39245346,"top":0.2406225,"width":0.03158245,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3","depth":21,"bounds":{"left":0.42802528,"top":0.2406225,"width":0.002493351,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"JY-20361 AJ Panorama for Call Scoring in OD. Use the enter key to load the work item.","depth":16,"bounds":{"left":0.39145613,"top":0.27055067,"width":0.08028591,"height":0.121308856},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AJ Panorama for Call Scoring in OD","depth":17,"bounds":{"left":0.39544547,"top":0.28132483,"width":0.04637633,"height":0.029928172},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AUTOMATED AI SCORING","depth":18,"bounds":{"left":0.39677528,"top":0.31923383,"width":0.04837101,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Backlog","depth":17,"bounds":{"left":0.39544547,"top":0.3387869,"width":0.01761968,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20361","depth":17,"bounds":{"left":0.40209442,"top":0.36472467,"width":0.018284574,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20361","depth":19,"bounds":{"left":0.40209442,"top":0.3651237,"width":0.018284574,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2.5","depth":17,"bounds":{"left":0.43118352,"top":0.3651237,"width":0.005984043,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"JY-20725 [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts. Use the enter key to load the work item.","depth":16,"bounds":{"left":0.39145613,"top":0.39505187,"width":0.08028591,"height":0.1376696},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts","depth":18,"bounds":{"left":0.39544547,"top":0.40582603,"width":0.06000665,"height":0.045889866},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Platform Stability, Edit Parent","depth":17,"bounds":{"left":0.39544547,"top":0.45889863,"width":0.044714097,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"PLATFORM STABILITY","depth":21,"bounds":{"left":0.39677528,"top":0.46009576,"width":0.042054523,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Backlog","depth":17,"bounds":{"left":0.39544547,"top":0.47964883,"width":0.01761968,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20725","depth":17,"bounds":{"left":0.40209442,"top":0.50558656,"width":0.01861702,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725","depth":19,"bounds":{"left":0.40209442,"top":0.5059856,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4","depth":17,"bounds":{"left":0.4331782,"top":0.5059856,"width":0.002493351,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Assignee: Lukas Kovalik","depth":17,"bounds":{"left":0.45910904,"top":0.50239426,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-19951 Setup test coverage for Prophet in Sonar. Use the enter key to load the work item.","depth":16,"bounds":{"left":0.39145613,"top":0.5359138,"width":0.08028591,"height":0.1217079},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Setup test coverage for Prophet in Sonar","depth":18,"bounds":{"left":0.39544547,"top":0.54668796,"width":0.051529255,"height":0.029928172},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Maintenance, Edit Parent","depth":17,"bounds":{"left":0.39544547,"top":0.5837989,"width":0.03174867,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"MAINTENANCE","depth":21,"bounds":{"left":0.39677528,"top":0.584996,"width":0.029089095,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Backlog","depth":17,"bounds":{"left":0.39544547,"top":0.6045491,"width":0.01761968,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-19951","depth":17,"bounds":{"left":0.40209442,"top":0.63048685,"width":0.017453458,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-19951","depth":19,"bounds":{"left":0.40209442,"top":0.6308859,"width":0.017453458,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":17,"bounds":{"left":0.43367687,"top":0.6308859,"width":0.0016622341,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"In DEV","depth":16,"bounds":{"left":0.4787234,"top":0.24022347,"width":0.024601065,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"IN DEV","depth":18,"bounds":{"left":0.4787234,"top":0.2406225,"width":0.013962766,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":21,"bounds":{"left":0.49684176,"top":0.2406225,"width":0.0023271276,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"JY-20566 AI Review - Q1 - Summary/Action items/Key Points. Use the enter key to load the work item.","depth":16,"bounds":{"left":0.47772607,"top":0.27055067,"width":0.080119684,"height":0.1217079},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AI Review - Q1 - Summary/Action items/Key Points","depth":18,"bounds":{"left":0.4817154,"top":0.28132483,"width":0.059507977,"height":0.029928172},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-8063002738601889384
|
4760644749529109728
|
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
Close tab
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Sentry
Sentry
Pull requests · jiminny/app
Pull requests · jiminny/app
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Space navigation
Space navigation
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent
Starred
Starred
Apps
Apps
More actions for Apps
More actions for Apps
Spaces
Spaces
Create space
Create space
More actions for spaces
More actions for spaces
Recent
Jiminny (New)
Jiminny (New)
Jiminny (New)
Create board
Create board
More actions for Jiminny (New)
More actions for Jiminny (New)
Platform Team
Platform Team
Board actions
Board actions
Capture Team
Capture Team
Board actions
Board actions
Enterprise Stability Issues 🤕
Enterprise Stability Issues 🤕
Board actions
Board actions
Processing Team
Processing Team
Board actions
Board actions
SE Kanban
SE Kanban
Board actions
Board actions
Service-Desk
Service-Desk
More actions for Service-Desk
More actions for Service-Desk
Queues
Queues
Create
Create
More for queues
More for queues
Service requests
Service requests
Create
Create
More for service requests
More for service requests
Incidents
Incidents
Create
Create
More for incidents
More for incidents
Reports
Reports
More actions for reports
More actions for reports
Operations
Operations
More actions for operations
More actions for operations
Knowledge Base
Knowledge Base
More actions for knowledge base
More actions for knowledge base
Customers
Customers
More actions for customers
More actions for customers
Channels
Channels
Email logs
Email logs
More actions for customer notification logs
More actions for customer notification logs
Developer escalations
Developer escalations
More actions for developer escalations
More actions for developer escalations
Slack integration
Slack integration
More actions for Slack integration
More actions for Slack integration
Reporting Center
Reporting Center
More actions for Reporting Center
More actions for Reporting Center
Add shortcut
Add shortcut
More actions for developer escalations
More actions for developer escalations
Archived work items
Archived work items
More actions for archived work items
More actions for archived work items
More spaces
More spaces
Filters
Filters
More actions for Filters
More actions for Filters
Dashboards
Dashboards
Create dashboard
Create dashboard
More actions for Dashboards
More actions for Dashboards
Operations
Operations
More actions for Operations
More actions for Operations
Confluence , (opens new window)
Confluence
, (opens new window)
Teams , (opens new window)
Teams
, (opens new window)
open menu
open menu
Customise sidebar
Customise sidebar
Resize side navigation panel
Spaces
Spaces
/
Jiminny (New)
Jiminny (New)
Platform Team
Platform Team
Add people
Add people
Board actions
Board actions
Share
Automation
Give feedback
Give feedback
Enter full screen
Enter full screen
Summary
Summary
Timeline
Timeline
Backlog
Backlog
Active sprints
Active sprints
Calendar
Calendar
Reports
Reports
Testing Board
Testing Board
List
List
Forms
Forms
Components
Components
Development
Development
Code
Code
Security
Security
Releases
Releases
Deployments
Deployments
5 more tabs
More
5
Add to navigation
As you type to search or apply filters, the board updates with work items to match.
Search on current page
Filter by assignee
Filter assignees by Lukas Kovalik
Filter assignees by Aneliya Angelova
Filter assignees by Nikolay Ivanov
Filter assignees by Nikolay Nikolov
Filter assignees by Steliyan Georgiev
Filter assignees by Unassigned
Epic
Epic
Type
Type
Quick filters
Quick filters
Complete sprint
Complete sprint
Sprint details
Sprint details
Group by Queries
Group
: Queries
Sprint insights
Sprint insights
View settings
View settings
More actions
More actions
Ready For DEV
READY FOR DEV
3
JY-20361 AJ Panorama for Call Scoring in OD. Use the enter key to load the work item.
AJ Panorama for Call Scoring in OD
AUTOMATED AI SCORING
Backlog
JY-20361
JY-20361
2.5
JY-20725 [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts. Use the enter key to load the work item.
[HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts
Platform Stability, Edit Parent
PLATFORM STABILITY
Backlog
JY-20725
JY-20725
4
Assignee: Lukas Kovalik
JY-19951 Setup test coverage for Prophet in Sonar. Use the enter key to load the work item.
Setup test coverage for Prophet in Sonar
Maintenance, Edit Parent
MAINTENANCE
Backlog
JY-19951
JY-19951
1
In DEV
IN DEV
2
JY-20566 AI Review - Q1 - Summary/Action items/Key Points. Use the enter key to load the work item.
AI Review - Q1 - Summary/Action items/Key Points...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
4934
|
177
|
16
|
2026-05-07T14:39:53.521330+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778164793521_m1.jpg...
|
Firefox
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira — Work...
|
True
|
jiminny.atlassian.net/jira/software/c/projects/JY/ jiminny.atlassian.net/jira/software/c/projects/JY/boards/37...
|
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
Close tab
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
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
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Sentry
Sentry
Pull requests · jiminny/app
Pull requests · jiminny/app
Userpilot | Ask Jiminny Report Generated
Userpilot | Ask Jiminny Report Generated
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
Jiminny
Jiminny
Search the CRM - HubSpot docs
Search the CRM - HubSpot docs
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Space navigation
Space navigation
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent
Starred
Starred
Apps
Apps
More actions for Apps
More actions for Apps
Spaces
Spaces
Create space
Create space
More actions for spaces
More actions for spaces
Recent
Jiminny (New)
Jiminny (New)
Jiminny (New)
Create board
Create board
More actions for Jiminny (New)
More actions for Jiminny (New)
Platform Team
Platform Team
Board actions
Board actions
Capture Team
Capture Team
Board actions
Board actions
Enterprise Stability Issues 🤕
Enterprise Stability Issues 🤕
Board actions
Board actions
Processing Team
Processing Team
Board actions
Board actions
SE Kanban
SE Kanban
Board actions
Board actions
Service-Desk
Service-Desk
More actions for Service-Desk
More actions for Service-Desk
More spaces
More spaces
Filters
Filters
More actions for Filters
More actions for Filters
Dashboards
Dashboards
Create dashboard
Create dashboard
More actions for Dashboards
More actions for Dashboards
Operations
Operations
More actions for Operations
More actions for Operations
Confluence , (opens new window)
Confluence
, (opens new window)
Teams , (opens new window)
Teams
, (opens new window)
open menu
open menu
Customise sidebar
Customise sidebar
Resize side navigation panel
Spaces
Spaces
/
Jiminny (New)
Jiminny (New)
Platform Team
Platform Team
Add people
Add people
Board actions
Board actions
Share
Automation
Give feedback
Give feedback
Enter full screen
Enter full screen
Summary
Summary
Timeline
Timeline
Backlog
Backlog
Active sprints
Active sprints
Calendar
Calendar
Reports
Reports
Testing Board
Testing Board
List
List
Forms
Forms
Components
Components
Development
Development
Tab options
Tab options
Code
Code
8 more tabs
More
8
Add to navigation
As you type to search or apply filters, the board updates with work items to match.
Search on current page
Filter by assignee
Filter assignees by Lukas Kovalik
Filter assignees by Aneliya Angelova
Filter assignees by Nikolay Ivanov
Filter assignees by Nikolay Nikolov
Filter assignees by Steliyan Georgiev
Filter assignees by Unassigned
Epic
Epic
Type
Type
Quick filters
Quick filters
Complete sprint
Complete sprint
Sprint details
Sprint details
Group by Queries
Group
: Queries
Sprint insights
Sprint insights
View settings
View settings
More actions
More actions...
|
[{"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":true},{"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":"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":"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":"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":"Sentry","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pull requests · 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":"Pull requests · 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":"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":"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":"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.16770834,"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.190625,"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.21388888,"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.23715279,"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.26041666,"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":"Skip to:","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Top Bar","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Top Bar","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sidebar","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sidebar","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Main Content","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Main Content","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Space navigation","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Space navigation","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse sidebar [","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Collapse sidebar [","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Switch sites or apps","depth":10,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Switch sites or apps","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Go to your Jira homepage","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"Search, press enter to navigate to advanced search with your text query","depth":11,"on_screen":true,"help_text":"","placeholder":"Search","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Create","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Rovo Ask Rovo","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Rovo","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Notifications","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notifications","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Help","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Help","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Settings","depth":12,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Settings","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"lukas.kovalik@jiminny.com","depth":12,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"lukas.kovalik@jiminny.com","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"For you","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"For you","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Recent","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":"Recent","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Starred","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":"Starred","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Apps","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":"Apps","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Apps","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Apps","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Spaces","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Spaces","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create space","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create space","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for spaces","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for spaces","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Recent","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny (New)","depth":17,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny (New)","depth":20,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Jiminny (New)","depth":18,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXMenuButton","text":"Create board","depth":18,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Create board","depth":20,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Jiminny (New)","depth":18,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Jiminny (New)","depth":20,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Platform Team","depth":19,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Team","depth":22,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Capture Team","depth":19,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Capture Team","depth":22,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Enterprise Stability Issues 🤕","depth":19,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Enterprise Stability Issues 🤕","depth":22,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Processing Team","depth":19,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Processing Team","depth":22,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SE Kanban","depth":19,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SE Kanban","depth":22,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Service-Desk","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":"Service-Desk","depth":20,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Service-Desk","depth":18,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Service-Desk","depth":20,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"More spaces","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 spaces","depth":20,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Filters","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":"Filters","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Filters","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Filters","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dashboards","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":"Dashboards","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create dashboard","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create dashboard","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Dashboards","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Dashboards","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Operations","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":"Operations","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Operations","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Operations","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Confluence , (opens new window)","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Confluence","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", (opens new window)","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Teams , (opens new window)","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Teams","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", (opens new window)","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"open menu","depth":14,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"open menu","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Customise sidebar","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Customise sidebar","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Resize side navigation panel","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Spaces","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Spaces","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny (New)","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny (New)","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Platform Team","depth":10,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Platform Team","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Add people","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Add people","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":10,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Share","depth":10,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Automation","depth":10,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Give feedback","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Give feedback","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Enter full screen","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Enter full screen","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Summary","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summary","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Timeline","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Timeline","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Backlog","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Backlog","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Active sprints","depth":13,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Active sprints","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Calendar","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Calendar","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Reports","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Reports","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Testing Board","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 Board","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"List","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"List","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Forms","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Forms","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Components","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Components","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Development","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Development","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Tab options","depth":14,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Tab options","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"8 more tabs","depth":11,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Add to navigation","depth":11,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"As you type to search or apply filters, the board updates with work items to match.","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Search on current page","depth":11,"on_screen":true,"placeholder":"Search board","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Filter by assignee","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Filter assignees by Lukas Kovalik","depth":11,"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Filter assignees by Aneliya Angelova","depth":11,"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Filter assignees by Nikolay Ivanov","depth":11,"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Filter assignees by Nikolay Nikolov","depth":11,"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Filter assignees by Steliyan Georgiev","depth":11,"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Filter assignees by Unassigned","depth":11,"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Epic","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Epic","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Type","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Type","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Quick filters","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Quick filters","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Complete sprint","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Complete sprint","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Sprint details","depth":10,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Sprint details","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Group by Queries","depth":10,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Group","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":": Queries","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Sprint insights","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":"AXStaticText","text":"Sprint insights","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"View settings","depth":10,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"View settings","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions","depth":10,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-8060700072437341012
|
5932770308657304706
|
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
Close tab
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
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
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Sentry
Sentry
Pull requests · jiminny/app
Pull requests · jiminny/app
Userpilot | Ask Jiminny Report Generated
Userpilot | Ask Jiminny Report Generated
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
Jiminny
Jiminny
Search the CRM - HubSpot docs
Search the CRM - HubSpot docs
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Space navigation
Space navigation
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent
Starred
Starred
Apps
Apps
More actions for Apps
More actions for Apps
Spaces
Spaces
Create space
Create space
More actions for spaces
More actions for spaces
Recent
Jiminny (New)
Jiminny (New)
Jiminny (New)
Create board
Create board
More actions for Jiminny (New)
More actions for Jiminny (New)
Platform Team
Platform Team
Board actions
Board actions
Capture Team
Capture Team
Board actions
Board actions
Enterprise Stability Issues 🤕
Enterprise Stability Issues 🤕
Board actions
Board actions
Processing Team
Processing Team
Board actions
Board actions
SE Kanban
SE Kanban
Board actions
Board actions
Service-Desk
Service-Desk
More actions for Service-Desk
More actions for Service-Desk
More spaces
More spaces
Filters
Filters
More actions for Filters
More actions for Filters
Dashboards
Dashboards
Create dashboard
Create dashboard
More actions for Dashboards
More actions for Dashboards
Operations
Operations
More actions for Operations
More actions for Operations
Confluence , (opens new window)
Confluence
, (opens new window)
Teams , (opens new window)
Teams
, (opens new window)
open menu
open menu
Customise sidebar
Customise sidebar
Resize side navigation panel
Spaces
Spaces
/
Jiminny (New)
Jiminny (New)
Platform Team
Platform Team
Add people
Add people
Board actions
Board actions
Share
Automation
Give feedback
Give feedback
Enter full screen
Enter full screen
Summary
Summary
Timeline
Timeline
Backlog
Backlog
Active sprints
Active sprints
Calendar
Calendar
Reports
Reports
Testing Board
Testing Board
List
List
Forms
Forms
Components
Components
Development
Development
Tab options
Tab options
Code
Code
8 more tabs
More
8
Add to navigation
As you type to search or apply filters, the board updates with work items to match.
Search on current page
Filter by assignee
Filter assignees by Lukas Kovalik
Filter assignees by Aneliya Angelova
Filter assignees by Nikolay Ivanov
Filter assignees by Nikolay Nikolov
Filter assignees by Steliyan Georgiev
Filter assignees by Unassigned
Epic
Epic
Type
Type
Quick filters
Quick filters
Complete sprint
Complete sprint
Sprint details
Sprint details
Group by Queries
Group
: Queries
Sprint insights
Sprint insights
View settings
View settings
More actions
More actions...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17286
|
768
|
41
|
2026-05-11T10:15:44.861158+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778494544861_m1.jpg...
|
Notion Calendar
|
NULL
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
iTerm2•ShellEditViewSessionScriptsProfilesWindowHe iTerm2•ShellEditViewSessionScriptsProfilesWindowHelplih§ Support Daily • in 1h 45 mDOCKERDEV (docker)H82APP (-zsh)DEV (docker)X3-zshl84-zsh100% C8• Mon 11 May 13:15:44181ffmpeg0 ₴6configcachecompiledeventsroutesviewsjiminny-worker-processing-2:jiminny-worker-processing-2_00: stoppedjiminny-worker-processing-3:jiminny-worker-processing-3_00:stoppedjiminny-worker-processing-4:jiminny-worker-processing-4_00:stoppedjiminny-worker-processing-5:jiminny-worker-processing-5_00:stoppedjiminny-worker-processing-delayed: jiminny-worker-processing-delayed_00: stoppedworker-analytics:worker-analytics_00: stoppedworker-conferences:worker-conferences_00: stoppedworker-crm-update:worker-crm-update_00: stoppedworker-download:worker-download_00: stoppedworker-emails:worker-emails_00: stoppedworker-nudges:worker-nudges_00: stoppedworker:worker_00: stoppedworker-audio:worker-audio_00: stoppedworker-calendar:worker-calendar_00: stoppedworker-crm-sync:worker-crm-sync_00: stoppedartisan-schedule:artisan-schedule_00: stoppedworker-es-update:worker-es-update_00: stoppedjiminny-worker-processing-1:jiminny-worker-processing-1_00: stoppedartisan-schedule:artisan-schedule_00: startedjiminny-worker-processing-1:jiminny-worker-processing-1_00: startedjiminny-worker-processing-2:jiminny-worker-processing-2_00: startedjiminny-worker-processing-3:jiminny-worker-processing-3_00: startedjiminny-worker-processing-4:jiminny-worker-processing-4_00: startedjiminny-worker-processing-5:jiminny-worker-processing-5_00: startedjiminny-worker-processing-delayed:jiminny-worker-processing-delayed_00:startedworker:worker_00: startedworker-analytics:worker-analytics_00: startedworker-audio:worker-audio_00: startedworker-calendar:worker-calendar_00: startedworker-conferences:worker-conferences_00: startedworker-crm-sync:worker-crm-sync_00: startedworker-crm-update:worker-crm-update_00: startedworker-download:worker-download_00:startedworker-emails:worker-emails_00: startedworker-es-update:worker-es-update_00: startedworker-nudges:worker-nudges_00:startedroot@docker_lamp_1:/home/jiminny#php artisan jiminny: debugll88510.53ms DONE128.25ms DONE1.73ms DONE1.07ms DONE1.45ms DONE5.46ms DONEDEV...
|
NULL
|
-8059924250003948551
|
NULL
|
click
|
ocr
|
NULL
|
iTerm2•ShellEditViewSessionScriptsProfilesWindowHe iTerm2•ShellEditViewSessionScriptsProfilesWindowHelplih§ Support Daily • in 1h 45 mDOCKERDEV (docker)H82APP (-zsh)DEV (docker)X3-zshl84-zsh100% C8• Mon 11 May 13:15:44181ffmpeg0 ₴6configcachecompiledeventsroutesviewsjiminny-worker-processing-2:jiminny-worker-processing-2_00: stoppedjiminny-worker-processing-3:jiminny-worker-processing-3_00:stoppedjiminny-worker-processing-4:jiminny-worker-processing-4_00:stoppedjiminny-worker-processing-5:jiminny-worker-processing-5_00:stoppedjiminny-worker-processing-delayed: jiminny-worker-processing-delayed_00: stoppedworker-analytics:worker-analytics_00: stoppedworker-conferences:worker-conferences_00: stoppedworker-crm-update:worker-crm-update_00: stoppedworker-download:worker-download_00: stoppedworker-emails:worker-emails_00: stoppedworker-nudges:worker-nudges_00: stoppedworker:worker_00: stoppedworker-audio:worker-audio_00: stoppedworker-calendar:worker-calendar_00: stoppedworker-crm-sync:worker-crm-sync_00: stoppedartisan-schedule:artisan-schedule_00: stoppedworker-es-update:worker-es-update_00: stoppedjiminny-worker-processing-1:jiminny-worker-processing-1_00: stoppedartisan-schedule:artisan-schedule_00: startedjiminny-worker-processing-1:jiminny-worker-processing-1_00: startedjiminny-worker-processing-2:jiminny-worker-processing-2_00: startedjiminny-worker-processing-3:jiminny-worker-processing-3_00: startedjiminny-worker-processing-4:jiminny-worker-processing-4_00: startedjiminny-worker-processing-5:jiminny-worker-processing-5_00: startedjiminny-worker-processing-delayed:jiminny-worker-processing-delayed_00:startedworker:worker_00: startedworker-analytics:worker-analytics_00: startedworker-audio:worker-audio_00: startedworker-calendar:worker-calendar_00: startedworker-conferences:worker-conferences_00: startedworker-crm-sync:worker-crm-sync_00: startedworker-crm-update:worker-crm-update_00: startedworker-download:worker-download_00:startedworker-emails:worker-emails_00: startedworker-es-update:worker-es-update_00: startedworker-nudges:worker-nudges_00:startedroot@docker_lamp_1:/home/jiminny#php artisan jiminny: debugll88510.53ms DONE128.25ms DONE1.73ms DONE1.07ms DONE1.45ms DONE5.46ms DONEDEV...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
14998
|
672
|
20
|
2026-05-11T06:08:45.274545+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778479725274_m1.jpg...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
True
|
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...
|
[{"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}]...
|
-8057862210374731819
|
-8204420481362449466
|
click
|
hybrid
|
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
iTerm2ShellEditViewSessionScriptsProfilesWindowHelplobl| Daily - Platform • in 37 mA100% C47 8• Mon 11 May 9:08:44DEV (-zsh)• жз181DOCKERO ₴1DEV (-zsh)182APP (-zsh)* JY-20725-handle-HS-search-rate-limitmasterJY-20818-move-AJ-reports-to-separated-datadog-metricJY-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-UPaJY-18909-automated-reports-ask-jiminnyJY-20692-fix-integration-app-[API_KEY]@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-limit) $ l-zsh-zsh885screenpipe"O 86DEV...
|
NULL
|
NULL
|
NULL
|
NULL
|