screenhand 0.1.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (241) hide show
  1. package/README.md +193 -109
  2. package/bin/darwin-arm64/macos-bridge +0 -0
  3. package/dist/mcp-desktop.js +5876 -0
  4. package/dist/scripts/codex-monitor-daemon.js +335 -0
  5. package/dist/scripts/export-help-center.js +112 -0
  6. package/dist/scripts/marketing-loop.js +117 -0
  7. package/dist/scripts/observer-daemon.js +288 -0
  8. package/dist/scripts/orchestrator-daemon.js +399 -0
  9. package/dist/scripts/supervisor-daemon.js +272 -0
  10. package/dist/scripts/threads-campaign.js +208 -0
  11. package/dist/scripts/worker-daemon.js +228 -0
  12. package/dist/src/agent/cli.js +82 -0
  13. package/dist/src/agent/loop.js +274 -0
  14. package/dist/src/community/fetcher.js +109 -0
  15. package/dist/src/community/index.js +6 -0
  16. package/dist/src/community/publisher.js +191 -0
  17. package/dist/src/community/remote-api.js +121 -0
  18. package/dist/src/community/types.js +3 -0
  19. package/dist/src/community/validator.js +95 -0
  20. package/{src/config.ts → dist/src/config.js} +5 -10
  21. package/dist/src/context-tracker.js +489 -0
  22. package/{src/index.ts → dist/src/index.js} +32 -52
  23. package/dist/src/ingestion/coverage-auditor.js +233 -0
  24. package/dist/src/ingestion/doc-parser.js +164 -0
  25. package/dist/src/ingestion/index.js +8 -0
  26. package/dist/src/ingestion/menu-scanner.js +152 -0
  27. package/dist/src/ingestion/reference-merger.js +186 -0
  28. package/dist/src/ingestion/shortcut-extractor.js +180 -0
  29. package/dist/src/ingestion/tutorial-extractor.js +170 -0
  30. package/dist/src/ingestion/types.js +3 -0
  31. package/dist/src/jobs/manager.js +305 -0
  32. package/dist/src/jobs/runner.js +806 -0
  33. package/dist/src/jobs/store.js +102 -0
  34. package/dist/src/jobs/types.js +30 -0
  35. package/dist/src/jobs/worker.js +97 -0
  36. package/dist/src/learning/engine.js +356 -0
  37. package/dist/src/learning/index.js +9 -0
  38. package/dist/src/learning/locator-policy.js +120 -0
  39. package/dist/src/learning/pattern-policy.js +89 -0
  40. package/dist/src/learning/recovery-policy.js +116 -0
  41. package/dist/src/learning/sensor-policy.js +115 -0
  42. package/dist/src/learning/timing-model.js +204 -0
  43. package/dist/src/learning/topology-policy.js +90 -0
  44. package/dist/src/learning/types.js +9 -0
  45. package/dist/src/logging/timeline-logger.js +48 -0
  46. package/dist/src/mcp/mcp-stdio-server.js +464 -0
  47. package/dist/src/mcp/server.js +363 -0
  48. package/dist/src/mcp-entry.js +60 -0
  49. package/dist/src/memory/playbook-seeds.js +200 -0
  50. package/dist/src/memory/recall.js +222 -0
  51. package/dist/src/memory/research.js +104 -0
  52. package/dist/src/memory/seeds.js +101 -0
  53. package/dist/src/memory/service.js +446 -0
  54. package/dist/src/memory/session.js +169 -0
  55. package/dist/src/memory/store.js +451 -0
  56. package/{src/runtime/locator-cache.ts → dist/src/memory/types.js} +1 -17
  57. package/dist/src/monitor/codex-monitor.js +382 -0
  58. package/dist/src/monitor/task-queue.js +97 -0
  59. package/dist/src/monitor/types.js +62 -0
  60. package/dist/src/native/bridge-client.js +412 -0
  61. package/{src/native/macos-bridge-client.ts → dist/src/native/macos-bridge-client.js} +0 -1
  62. package/dist/src/observer/state.js +199 -0
  63. package/dist/src/observer/types.js +43 -0
  64. package/dist/src/orchestrator/state.js +68 -0
  65. package/dist/src/orchestrator/types.js +22 -0
  66. package/dist/src/perception/ax-source.js +162 -0
  67. package/dist/src/perception/cdp-source.js +162 -0
  68. package/dist/src/perception/coordinator.js +771 -0
  69. package/dist/src/perception/frame-differ.js +287 -0
  70. package/dist/src/perception/index.js +22 -0
  71. package/dist/src/perception/manager.js +199 -0
  72. package/dist/src/perception/types.js +47 -0
  73. package/dist/src/perception/vision-source.js +399 -0
  74. package/dist/src/planner/deterministic.js +298 -0
  75. package/dist/src/planner/executor.js +870 -0
  76. package/dist/src/planner/goal-store.js +92 -0
  77. package/dist/src/planner/index.js +21 -0
  78. package/dist/src/planner/planner.js +520 -0
  79. package/dist/src/planner/tool-registry.js +71 -0
  80. package/dist/src/planner/types.js +22 -0
  81. package/dist/src/platform/explorer.js +213 -0
  82. package/dist/src/platform/help-center-markdown.js +527 -0
  83. package/dist/src/platform/learner.js +257 -0
  84. package/dist/src/playbook/engine.js +486 -0
  85. package/dist/src/playbook/index.js +20 -0
  86. package/dist/src/playbook/mcp-recorder.js +204 -0
  87. package/dist/src/playbook/recorder.js +536 -0
  88. package/dist/src/playbook/runner.js +408 -0
  89. package/dist/src/playbook/store.js +312 -0
  90. package/dist/src/playbook/types.js +17 -0
  91. package/dist/src/recovery/detectors.js +156 -0
  92. package/dist/src/recovery/engine.js +327 -0
  93. package/dist/src/recovery/index.js +20 -0
  94. package/dist/src/recovery/strategies.js +274 -0
  95. package/dist/src/recovery/types.js +20 -0
  96. package/dist/src/runtime/accessibility-adapter.js +430 -0
  97. package/dist/src/runtime/app-adapter.js +64 -0
  98. package/dist/src/runtime/applescript-adapter.js +305 -0
  99. package/dist/src/runtime/ax-role-map.js +96 -0
  100. package/dist/src/runtime/browser-adapter.js +52 -0
  101. package/dist/src/runtime/cdp-chrome-adapter.js +521 -0
  102. package/dist/src/runtime/composite-adapter.js +221 -0
  103. package/dist/src/runtime/execution-contract.js +159 -0
  104. package/dist/src/runtime/executor.js +286 -0
  105. package/dist/src/runtime/locator-cache.js +50 -0
  106. package/dist/src/runtime/planning-loop.js +63 -0
  107. package/dist/src/runtime/service.js +432 -0
  108. package/dist/src/runtime/session-manager.js +63 -0
  109. package/dist/src/runtime/state-observer.js +121 -0
  110. package/dist/src/runtime/vision-adapter.js +225 -0
  111. package/dist/src/state/app-map-types.js +72 -0
  112. package/dist/src/state/app-map.js +1974 -0
  113. package/dist/src/state/entity-tracker.js +108 -0
  114. package/dist/src/state/fusion.js +96 -0
  115. package/dist/src/state/index.js +21 -0
  116. package/dist/src/state/ladder-generator.js +236 -0
  117. package/dist/src/state/persistence.js +156 -0
  118. package/dist/src/state/types.js +17 -0
  119. package/dist/src/state/world-model.js +1456 -0
  120. package/dist/src/supervisor/locks.js +186 -0
  121. package/dist/src/supervisor/supervisor.js +403 -0
  122. package/dist/src/supervisor/types.js +30 -0
  123. package/dist/src/test-mcp-protocol.js +154 -0
  124. package/dist/src/types.js +17 -0
  125. package/dist/src/util/atomic-write.js +133 -0
  126. package/dist/src/util/sanitize.js +146 -0
  127. package/dist-app-maps/com.figma.Desktop.json +959 -0
  128. package/dist-app-maps/com.hnc.Discord.json +1146 -0
  129. package/dist-app-maps/notion.id.json +2831 -0
  130. package/dist-playbooks/canva-screenhand-carousel.json +445 -0
  131. package/dist-playbooks/codex-desktop.json +76 -0
  132. package/dist-playbooks/competitor-research-stack.json +122 -0
  133. package/dist-playbooks/davinci-color-grade.json +153 -0
  134. package/dist-playbooks/davinci-edit-timeline.json +162 -0
  135. package/dist-playbooks/davinci-render.json +114 -0
  136. package/dist-playbooks/devto.json +52 -0
  137. package/dist-playbooks/discord.json +41 -0
  138. package/dist-playbooks/google-flow-create-project.json +59 -0
  139. package/dist-playbooks/google-flow-edit-image.json +90 -0
  140. package/dist-playbooks/google-flow-edit-video.json +90 -0
  141. package/dist-playbooks/google-flow-generate-image.json +68 -0
  142. package/dist-playbooks/google-flow-generate-video.json +191 -0
  143. package/dist-playbooks/google-flow-open-project.json +48 -0
  144. package/dist-playbooks/google-flow-open-scenebuilder.json +64 -0
  145. package/dist-playbooks/google-flow-search-assets.json +64 -0
  146. package/dist-playbooks/instagram.json +57 -0
  147. package/dist-playbooks/linkedin.json +52 -0
  148. package/dist-playbooks/n8n.json +43 -0
  149. package/dist-playbooks/reddit.json +52 -0
  150. package/dist-playbooks/threads.json +59 -0
  151. package/dist-playbooks/x-twitter.json +59 -0
  152. package/dist-playbooks/youtube.json +59 -0
  153. package/dist-references/canva.json +646 -0
  154. package/dist-references/codex-desktop.json +305 -0
  155. package/dist-references/davinci-resolve-keyboard.json +594 -0
  156. package/dist-references/davinci-resolve-menu-map.json +1139 -0
  157. package/dist-references/davinci-resolve-menus-batch1.json +116 -0
  158. package/dist-references/davinci-resolve-menus-batch2.json +372 -0
  159. package/dist-references/davinci-resolve-menus-batch3.json +330 -0
  160. package/dist-references/davinci-resolve-menus-batch4.json +297 -0
  161. package/dist-references/davinci-resolve-shortcuts.json +333 -0
  162. package/dist-references/devto.json +317 -0
  163. package/dist-references/discord.json +549 -0
  164. package/dist-references/figma.json +1186 -0
  165. package/dist-references/finder.json +146 -0
  166. package/dist-references/google-ads-transparency.json +95 -0
  167. package/dist-references/google-flow.json +649 -0
  168. package/dist-references/instagram.json +341 -0
  169. package/dist-references/linkedin.json +324 -0
  170. package/dist-references/meta-ad-library.json +86 -0
  171. package/dist-references/n8n.json +387 -0
  172. package/dist-references/notes.json +27 -0
  173. package/dist-references/notion.json +163 -0
  174. package/dist-references/reddit.json +341 -0
  175. package/dist-references/threads.json +337 -0
  176. package/dist-references/x-twitter.json +403 -0
  177. package/dist-references/youtube.json +373 -0
  178. package/native/macos-bridge/Package.swift +1 -0
  179. package/native/macos-bridge/Sources/AccessibilityBridge.swift +257 -36
  180. package/native/macos-bridge/Sources/AppManagement.swift +212 -2
  181. package/native/macos-bridge/Sources/CoreGraphicsBridge.swift +348 -53
  182. package/native/macos-bridge/Sources/StreamCapture.swift +136 -0
  183. package/native/macos-bridge/Sources/VisionBridge.swift +165 -7
  184. package/native/macos-bridge/Sources/main.swift +169 -16
  185. package/native/windows-bridge/Program.cs +5 -0
  186. package/native/windows-bridge/ScreenCapture.cs +124 -0
  187. package/package.json +29 -4
  188. package/scripts/postinstall.cjs +127 -0
  189. package/.claude/commands/automate.md +0 -28
  190. package/.claude/commands/debug-ui.md +0 -19
  191. package/.claude/commands/screenshot.md +0 -15
  192. package/.github/FUNDING.yml +0 -1
  193. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -27
  194. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
  195. package/.mcp.json +0 -8
  196. package/DESKTOP_MCP_GUIDE.md +0 -92
  197. package/SECURITY.md +0 -44
  198. package/docs/architecture.md +0 -47
  199. package/install-skills.sh +0 -19
  200. package/mcp-bridge.ts +0 -271
  201. package/mcp-desktop.ts +0 -1221
  202. package/playbooks/instagram.json +0 -41
  203. package/playbooks/instagram_v2.json +0 -201
  204. package/playbooks/x_v1.json +0 -211
  205. package/scripts/devpost-live-loop.mjs +0 -421
  206. package/src/logging/timeline-logger.ts +0 -55
  207. package/src/mcp/server.ts +0 -449
  208. package/src/memory/recall.ts +0 -191
  209. package/src/memory/research.ts +0 -146
  210. package/src/memory/seeds.ts +0 -123
  211. package/src/memory/session.ts +0 -201
  212. package/src/memory/store.ts +0 -434
  213. package/src/memory/types.ts +0 -69
  214. package/src/native/bridge-client.ts +0 -239
  215. package/src/runtime/accessibility-adapter.ts +0 -487
  216. package/src/runtime/app-adapter.ts +0 -169
  217. package/src/runtime/applescript-adapter.ts +0 -376
  218. package/src/runtime/ax-role-map.ts +0 -102
  219. package/src/runtime/browser-adapter.ts +0 -129
  220. package/src/runtime/cdp-chrome-adapter.ts +0 -676
  221. package/src/runtime/composite-adapter.ts +0 -274
  222. package/src/runtime/executor.ts +0 -396
  223. package/src/runtime/planning-loop.ts +0 -81
  224. package/src/runtime/service.ts +0 -448
  225. package/src/runtime/session-manager.ts +0 -50
  226. package/src/runtime/state-observer.ts +0 -136
  227. package/src/runtime/vision-adapter.ts +0 -297
  228. package/src/types.ts +0 -297
  229. package/tests/bridge-client.test.ts +0 -176
  230. package/tests/browser-stealth.test.ts +0 -210
  231. package/tests/composite-adapter.test.ts +0 -64
  232. package/tests/mcp-server.test.ts +0 -151
  233. package/tests/memory-recall.test.ts +0 -339
  234. package/tests/memory-research.test.ts +0 -159
  235. package/tests/memory-seeds.test.ts +0 -120
  236. package/tests/memory-store.test.ts +0 -392
  237. package/tests/types.test.ts +0 -92
  238. package/tsconfig.check.json +0 -17
  239. package/tsconfig.json +0 -19
  240. package/vitest.config.ts +0 -8
  241. /package/{playbooks → dist-references}/devpost.json +0 -0
@@ -0,0 +1,153 @@
1
+ {
2
+ "id": "davinci-color-grade",
3
+ "name": "DaVinci Resolve - Basic Color Grade",
4
+ "description": "Keyboard-first color-correction flow that switches to the Color page, adds correction nodes, applies Auto Color, enables printer-light hotkeys, adds a windowed node, and grabs a still. Designed for ScreenHand environments where DaVinci UI elements are not accessibility-visible.",
5
+ "platform": "davinci-resolve",
6
+ "version": "1.0.0",
7
+ "tags": [
8
+ "davinci-resolve",
9
+ "color",
10
+ "grading",
11
+ "keyboard",
12
+ "menu"
13
+ ],
14
+ "successCount": 0,
15
+ "failCount": 0,
16
+ "urls": {
17
+ "manual_pdf": "https://documents.blackmagicdesign.com/UserManuals/DaVinci_Resolve_20.3_Reference_Manual.pdf",
18
+ "training": "https://www.blackmagicdesign.com/products/davinciresolve/training"
19
+ },
20
+ "selectors": {
21
+ "menus": {
22
+ "color_page": "Workspace/Switch to Page/Color",
23
+ "printer_light_hotkeys": "Color/Printer Light Hotkeys",
24
+ "add_circle_window_node": "Color/Nodes/Add Serial Node + CPW",
25
+ "add_outside_node": "Color/Nodes/Add Outside Node",
26
+ "grab_still": "Color/Stills/Grab Still"
27
+ }
28
+ },
29
+ "flows": {
30
+ "basic_color_correction": {
31
+ "why": "Provides a reproducible baseline grade without relying on inaccessible UI widgets.",
32
+ "steps": [
33
+ "Switch to Color, add a serial node, apply Auto Color, enable printer-light hotkeys, add a power-window node, then grab a still."
34
+ ]
35
+ }
36
+ },
37
+ "policyNotes": {
38
+ "preconditions": [
39
+ "Open a project and select the clip you want to grade before running this playbook.",
40
+ "If printer-light hotkeys are already enabled, the menu step is idempotent."
41
+ ],
42
+ "limitations": [
43
+ "Default Resolve shortcuts do not expose direct palette toggles for Curves or Qualifier, so this workflow focuses on node creation, primaries, windows, and still capture."
44
+ ]
45
+ },
46
+ "steps": [
47
+ {
48
+ "action": "key",
49
+ "keys": [
50
+ "shift",
51
+ "6"
52
+ ],
53
+ "description": "Switch to the Color page"
54
+ },
55
+ {
56
+ "action": "wait",
57
+ "ms": 1000,
58
+ "description": "Wait for the Color page to settle"
59
+ },
60
+ {
61
+ "action": "key",
62
+ "keys": [
63
+ "alt",
64
+ "s"
65
+ ],
66
+ "description": "Add a serial correction node"
67
+ },
68
+ {
69
+ "action": "wait",
70
+ "ms": 400,
71
+ "description": "Let the node graph update"
72
+ },
73
+ {
74
+ "action": "key",
75
+ "keys": [
76
+ "shift",
77
+ "alt",
78
+ "c"
79
+ ],
80
+ "description": "Apply Auto Color for a primary-balance starting point"
81
+ },
82
+ {
83
+ "action": "wait",
84
+ "ms": 600,
85
+ "description": "Wait for Auto Color to finish"
86
+ },
87
+ {
88
+ "action": "menu_click",
89
+ "menuPath": [
90
+ "Color",
91
+ "Printer Light Hotkeys"
92
+ ],
93
+ "description": "Enable printer-light hotkeys for keyboard primary trims"
94
+ },
95
+ {
96
+ "action": "key",
97
+ "keys": [
98
+ "7"
99
+ ],
100
+ "description": "Nudge red printer light up one step"
101
+ },
102
+ {
103
+ "action": "key",
104
+ "keys": [
105
+ "8"
106
+ ],
107
+ "description": "Nudge green printer light up one step"
108
+ },
109
+ {
110
+ "action": "key",
111
+ "keys": [
112
+ "9"
113
+ ],
114
+ "description": "Nudge blue printer light up one step"
115
+ },
116
+ {
117
+ "action": "menu_click",
118
+ "menuPath": [
119
+ "Color",
120
+ "Nodes",
121
+ "Add Serial Node + CPW"
122
+ ],
123
+ "description": "Add a serial node with a circular power window"
124
+ },
125
+ {
126
+ "action": "wait",
127
+ "ms": 400,
128
+ "description": "Wait for the windowed node to appear"
129
+ },
130
+ {
131
+ "action": "menu_click",
132
+ "menuPath": [
133
+ "Color",
134
+ "Nodes",
135
+ "Add Outside Node"
136
+ ],
137
+ "description": "Create an outside node for the isolated correction"
138
+ },
139
+ {
140
+ "action": "menu_click",
141
+ "menuPath": [
142
+ "Color",
143
+ "Stills",
144
+ "Grab Still"
145
+ ],
146
+ "description": "Grab a still for before/after comparison"
147
+ },
148
+ {
149
+ "action": "screenshot",
150
+ "description": "Capture the Color page after grading"
151
+ }
152
+ ]
153
+ }
@@ -0,0 +1,162 @@
1
+ {
2
+ "id": "davinci-edit-timeline",
3
+ "name": "DaVinci Resolve - Import And Arrange Timeline",
4
+ "description": "Keyboard-only edit workflow that imports media, focuses the media pool and timeline, appends clips, adds a transition, and drops a marker. Intended for projects where the current file picker selection is already correct.",
5
+ "platform": "davinci-resolve",
6
+ "version": "1.0.0",
7
+ "tags": [
8
+ "davinci-resolve",
9
+ "edit",
10
+ "timeline",
11
+ "import",
12
+ "keyboard",
13
+ "menu"
14
+ ],
15
+ "successCount": 0,
16
+ "failCount": 0,
17
+ "urls": {
18
+ "manual_pdf": "https://documents.blackmagicdesign.com/UserManuals/DaVinci_Resolve_20.3_Reference_Manual.pdf",
19
+ "training": "https://www.blackmagicdesign.com/products/davinciresolve/training"
20
+ },
21
+ "selectors": {
22
+ "menus": {
23
+ "edit_page": "Workspace/Switch to Page/Edit",
24
+ "import_media": "File/Import/Media…",
25
+ "add_transition": "Timeline/Add Transition"
26
+ }
27
+ },
28
+ "flows": {
29
+ "import_arrange_clips": {
30
+ "why": "Stages a simple timeline without pointer clicks by leaning on panel-focus shortcuts and edit commands.",
31
+ "steps": [
32
+ "Switch to Edit, import media, focus Media Clips, append the selected clip(s), then focus the timeline to add a transition and marker."
33
+ ]
34
+ }
35
+ },
36
+ "policyNotes": {
37
+ "preconditions": [
38
+ "Open a project before running the playbook.",
39
+ "The native import dialog must already be pointed at the desired folder and current selection, because the playbook uses keyboard confirmation only."
40
+ ],
41
+ "limitations": [
42
+ "This workflow assumes at least one imported clip can be reached with arrow-key selection from the Media Clips panel."
43
+ ]
44
+ },
45
+ "steps": [
46
+ {
47
+ "action": "key",
48
+ "keys": [
49
+ "shift",
50
+ "4"
51
+ ],
52
+ "description": "Switch to the Edit page"
53
+ },
54
+ {
55
+ "action": "wait",
56
+ "ms": 1000,
57
+ "description": "Wait for the Edit page to settle"
58
+ },
59
+ {
60
+ "action": "menu_click",
61
+ "menuPath": [
62
+ "File",
63
+ "Import",
64
+ "Media…"
65
+ ],
66
+ "description": "Open the native media import dialog"
67
+ },
68
+ {
69
+ "action": "wait",
70
+ "ms": 600,
71
+ "description": "Wait for the file picker to appear"
72
+ },
73
+ {
74
+ "action": "key",
75
+ "keys": [
76
+ "enter"
77
+ ],
78
+ "description": "Confirm the current file picker selection"
79
+ },
80
+ {
81
+ "action": "wait",
82
+ "ms": 1200,
83
+ "description": "Wait for media import to complete"
84
+ },
85
+ {
86
+ "action": "key",
87
+ "keys": [
88
+ "cmd",
89
+ "2"
90
+ ],
91
+ "description": "Focus the Media Clips panel"
92
+ },
93
+ {
94
+ "action": "key",
95
+ "keys": [
96
+ "down"
97
+ ],
98
+ "description": "Select the next clip in Media Clips"
99
+ },
100
+ {
101
+ "action": "key",
102
+ "keys": [
103
+ "shift",
104
+ "f12"
105
+ ],
106
+ "description": "Append the selected clip to the end of the timeline"
107
+ },
108
+ {
109
+ "action": "wait",
110
+ "ms": 400,
111
+ "description": "Wait for the append edit to complete"
112
+ },
113
+ {
114
+ "action": "key",
115
+ "keys": [
116
+ "cmd",
117
+ "4"
118
+ ],
119
+ "description": "Focus the timeline"
120
+ },
121
+ {
122
+ "action": "key",
123
+ "keys": [
124
+ "n"
125
+ ],
126
+ "description": "Toggle snapping on for predictable edits"
127
+ },
128
+ {
129
+ "action": "key",
130
+ "keys": [
131
+ "b"
132
+ ],
133
+ "description": "Switch to Blade Edit mode"
134
+ },
135
+ {
136
+ "action": "key",
137
+ "keys": [
138
+ "a"
139
+ ],
140
+ "description": "Return to Normal Edit mode"
141
+ },
142
+ {
143
+ "action": "key",
144
+ "keys": [
145
+ "cmd",
146
+ "t"
147
+ ],
148
+ "description": "Add the default transition at the selected cut"
149
+ },
150
+ {
151
+ "action": "key",
152
+ "keys": [
153
+ "m"
154
+ ],
155
+ "description": "Drop a marker on the current edit"
156
+ },
157
+ {
158
+ "action": "screenshot",
159
+ "description": "Capture the Edit page after timeline assembly"
160
+ }
161
+ ]
162
+ }
@@ -0,0 +1,114 @@
1
+ {
2
+ "id": "davinci-render",
3
+ "name": "DaVinci Resolve - Render Export",
4
+ "description": "Keyboard-first export workflow that switches to Deliver, marks the range, then uses Quick Export as the stable no-pointer fallback when Deliver queue buttons are not accessibility-exposed.",
5
+ "platform": "davinci-resolve",
6
+ "version": "1.0.0",
7
+ "tags": [
8
+ "davinci-resolve",
9
+ "deliver",
10
+ "render",
11
+ "export",
12
+ "keyboard",
13
+ "menu"
14
+ ],
15
+ "successCount": 0,
16
+ "failCount": 0,
17
+ "urls": {
18
+ "manual_pdf": "https://documents.blackmagicdesign.com/UserManuals/DaVinci_Resolve_20.3_Reference_Manual.pdf",
19
+ "training": "https://www.blackmagicdesign.com/products/davinciresolve/training"
20
+ },
21
+ "selectors": {
22
+ "menus": {
23
+ "deliver_page": "Workspace/Switch to Page/Deliver",
24
+ "quick_export": "File/Quick Export…"
25
+ }
26
+ },
27
+ "flows": {
28
+ "quick_export_fallback": {
29
+ "why": "Deliver queue buttons are not reliably exposed via accessibility, so Quick Export is the deterministic export path for keyboard-only automation.",
30
+ "steps": [
31
+ "Switch to Deliver, define the In/Out range, open Quick Export, and confirm the last-used preset and destination from the keyboard."
32
+ ]
33
+ }
34
+ },
35
+ "policyNotes": {
36
+ "preconditions": [
37
+ "Open the target project and timeline before running this playbook.",
38
+ "Quick Export should already remember the desired preset and destination, because the dialog is confirmed from the keyboard using the last-used state."
39
+ ],
40
+ "limitations": [
41
+ "The default Resolve UI does not expose Add to Render Queue and Start Render as stable menu targets, so this playbook uses Quick Export instead of the Deliver queue buttons."
42
+ ]
43
+ },
44
+ "steps": [
45
+ {
46
+ "action": "key",
47
+ "keys": [
48
+ "shift",
49
+ "8"
50
+ ],
51
+ "description": "Switch to the Deliver page"
52
+ },
53
+ {
54
+ "action": "wait",
55
+ "ms": 1000,
56
+ "description": "Wait for the Deliver page to settle"
57
+ },
58
+ {
59
+ "action": "key",
60
+ "keys": [
61
+ "i"
62
+ ],
63
+ "description": "Mark the current frame as the render In point"
64
+ },
65
+ {
66
+ "action": "key",
67
+ "keys": [
68
+ "o"
69
+ ],
70
+ "description": "Mark the current frame as the render Out point"
71
+ },
72
+ {
73
+ "action": "menu_click",
74
+ "menuPath": [
75
+ "File",
76
+ "Quick Export…"
77
+ ],
78
+ "description": "Open Quick Export as the stable render fallback"
79
+ },
80
+ {
81
+ "action": "wait",
82
+ "ms": 800,
83
+ "description": "Wait for the Quick Export dialog to appear"
84
+ },
85
+ {
86
+ "action": "key",
87
+ "keys": [
88
+ "enter"
89
+ ],
90
+ "description": "Accept the currently highlighted Quick Export preset"
91
+ },
92
+ {
93
+ "action": "wait",
94
+ "ms": 800,
95
+ "description": "Wait for the export confirmation state"
96
+ },
97
+ {
98
+ "action": "key",
99
+ "keys": [
100
+ "enter"
101
+ ],
102
+ "description": "Confirm export using the last-used destination"
103
+ },
104
+ {
105
+ "action": "wait",
106
+ "ms": 2000,
107
+ "description": "Give Resolve time to start the export"
108
+ },
109
+ {
110
+ "action": "screenshot",
111
+ "description": "Capture the Deliver or export dialog state after submission"
112
+ }
113
+ ]
114
+ }
@@ -0,0 +1,52 @@
1
+ {
2
+ "id": "devto",
3
+ "name": "Dev.to Automation",
4
+ "description": "Battle-tested playbook for Dev.to browser automation via CDP. Covers creating posts, liking, commenting, bookmarking, searching, and profile management. Dev.to uses standard HTML elements (textarea, button) with React — native value setter needed for controlled inputs.",
5
+ "platform": "devto",
6
+ "version": "1.0.0",
7
+ "urlPatterns": [
8
+ "*dev.to*"
9
+ ],
10
+ "tags": [
11
+ "devto",
12
+ "blog",
13
+ "developer",
14
+ "browser",
15
+ "cdp"
16
+ ],
17
+ "successCount": 0,
18
+ "failCount": 0,
19
+ "steps": [
20
+ {
21
+ "action": "navigate",
22
+ "url": "https://dev.to/",
23
+ "description": "Open Dev.to home feed"
24
+ },
25
+ {
26
+ "action": "wait",
27
+ "ms": 2000,
28
+ "description": "Wait for feed to load"
29
+ },
30
+ {
31
+ "action": "extract",
32
+ "target": "[class*='crayons-story']",
33
+ "format": "text",
34
+ "description": "Extract article cards from feed"
35
+ },
36
+ {
37
+ "action": "scroll",
38
+ "direction": "down",
39
+ "amount": 5,
40
+ "description": "Scroll for more articles"
41
+ },
42
+ {
43
+ "action": "wait",
44
+ "ms": 1000,
45
+ "description": "Wait for lazy-loaded articles"
46
+ },
47
+ {
48
+ "action": "screenshot",
49
+ "description": "Capture feed state"
50
+ }
51
+ ]
52
+ }
@@ -0,0 +1,41 @@
1
+ {
2
+ "id": "discord",
3
+ "name": "Discord Automation",
4
+ "description": "Battle-tested playbook for Discord browser automation via CDP. Covers server navigation, channel browsing, messaging, DMs, reactions, server joining, friend requests, and search. Discord uses React with aria-labels and data-list-item-id attributes for reliable selectors.",
5
+ "platform": "discord",
6
+ "version": "1.0.0",
7
+ "urlPatterns": [
8
+ "*discord.com*"
9
+ ],
10
+ "tags": [
11
+ "discord",
12
+ "chat",
13
+ "community",
14
+ "browser",
15
+ "cdp"
16
+ ],
17
+ "successCount": 0,
18
+ "failCount": 0,
19
+ "steps": [
20
+ {
21
+ "action": "navigate",
22
+ "url": "https://discord.com/channels/@me",
23
+ "description": "Open Discord home (DMs)"
24
+ },
25
+ {
26
+ "action": "wait",
27
+ "ms": 2000,
28
+ "description": "Wait for Discord to load"
29
+ },
30
+ {
31
+ "action": "extract",
32
+ "target": "[data-list-item-id*='guildsnav']",
33
+ "format": "text",
34
+ "description": "Extract server list from sidebar"
35
+ },
36
+ {
37
+ "action": "screenshot",
38
+ "description": "Capture Discord state"
39
+ }
40
+ ]
41
+ }
@@ -0,0 +1,59 @@
1
+ {
2
+ "id": "google-flow-create-project",
3
+ "name": "Google Flow — Create Project",
4
+ "description": "Open the Google Flow dashboard, create a new project, and optionally rename it with {PROJECT_TITLE}. If {PROJECT_TITLE} is omitted, the auto-generated Flow title is kept.",
5
+ "platform": "google-flow",
6
+ "version": "1.0.0",
7
+ "urlPatterns": [
8
+ "*labs.google/fx/tools/flow*"
9
+ ],
10
+ "tags": [
11
+ "google-flow",
12
+ "browser",
13
+ "cdp",
14
+ "project",
15
+ "create"
16
+ ],
17
+ "successCount": 0,
18
+ "failCount": 0,
19
+ "steps": [
20
+ {
21
+ "action": "navigate",
22
+ "url": "https://labs.google/fx/tools/flow",
23
+ "description": "Open the Flow dashboard"
24
+ },
25
+ {
26
+ "action": "wait",
27
+ "ms": 1500,
28
+ "description": "Wait for the dashboard to load"
29
+ },
30
+ {
31
+ "action": "browser_js",
32
+ "code": "(() => { const close = [...document.querySelectorAll('button,[role=\"button\"]')].find(el => /close/i.test((el.textContent || '').trim())); if (close instanceof HTMLElement) { close.click(); return 'dismissed banner'; } return 'no banner'; })()",
33
+ "description": "Dismiss the launch banner if it is visible",
34
+ "optional": true
35
+ },
36
+ {
37
+ "action": "browser_js",
38
+ "code": "(() => { const visible = el => { const r = el.getBoundingClientRect(); const s = getComputedStyle(el); return r.width > 0 && r.height > 0 && s.visibility !== 'hidden' && s.display !== 'none'; }; const button = [...document.querySelectorAll('button,[role=\"button\"]')].filter(visible).find(el => (el.textContent || '').replace(/\\s+/g, ' ').includes('New project')); if (!(button instanceof HTMLElement)) throw new Error('New project button not found'); button.click(); return 'clicked New project'; })()",
39
+ "description": "Create a new Flow project",
40
+ "verify": "input[aria-label='Editable text']",
41
+ "verifyTimeoutMs": 15000
42
+ },
43
+ {
44
+ "action": "wait",
45
+ "ms": 1000,
46
+ "description": "Allow the project editor to settle"
47
+ },
48
+ {
49
+ "action": "browser_js",
50
+ "code": "(() => { const raw = `{PROJECT_TITLE}`.trim(); if (!raw || raw === '{PROJECT_TITLE}') return 'kept generated title'; const input = document.querySelector(\"input[aria-label='Editable text']\"); if (!(input instanceof HTMLInputElement)) throw new Error('Project title input not found'); input.focus(); input.value = ''; input.value = raw; input.dispatchEvent(new Event('input', { bubbles: true })); input.dispatchEvent(new Event('change', { bubbles: true })); input.blur(); return input.value; })()",
51
+ "description": "Rename the project if PROJECT_TITLE was provided"
52
+ },
53
+ {
54
+ "action": "screenshot",
55
+ "description": "Capture the new project editor",
56
+ "optional": true
57
+ }
58
+ ]
59
+ }
@@ -0,0 +1,90 @@
1
+ {
2
+ "id": "google-flow-edit-image",
3
+ "name": "Google Flow — Edit Image",
4
+ "description": "Open a Flow project, switch to image assets, open a matching image edit URL, and apply a prompt-based image edit through Flow's internal Slate editor and onSubmit handler. PROMPT mode is fully automated. CROP, SELECT, and DRAW can also be staged, but they usually still need drag or region input unless {AUTO_SUBMIT} is set to 1.",
5
+ "platform": "google-flow",
6
+ "version": "1.0.0",
7
+ "urlPatterns": [
8
+ "*labs.google/fx/tools/flow*"
9
+ ],
10
+ "tags": [
11
+ "google-flow",
12
+ "browser",
13
+ "cdp",
14
+ "image",
15
+ "edit"
16
+ ],
17
+ "successCount": 0,
18
+ "failCount": 0,
19
+ "steps": [
20
+ {
21
+ "action": "navigate",
22
+ "url": "https://labs.google/fx/tools/flow",
23
+ "description": "Open the Flow dashboard"
24
+ },
25
+ {
26
+ "action": "wait",
27
+ "ms": 1500,
28
+ "description": "Wait for dashboard project cards"
29
+ },
30
+ {
31
+ "action": "browser_js",
32
+ "code": "(() => { const visible = el => { const r = el.getBoundingClientRect(); const s = getComputedStyle(el); return r.width > 0 && r.height > 0 && s.visibility !== 'hidden' && s.display !== 'none'; }; const rawWanted = `{PROJECT_NAME}`.trim(); const wanted = rawWanted.toLowerCase(); const hasWanted = !!rawWanted && rawWanted !== '{PROJECT_NAME}'; const links = [...document.querySelectorAll(\"a[href*='/fx/tools/flow/project/']\")].filter(visible); if (!links.length) throw new Error('No Flow project cards found'); const pick = hasWanted ? links.find(link => ((link.closest('div')?.textContent || link.parentElement?.textContent || '')).toLowerCase().includes(wanted)) : links[0]; if (!(pick instanceof HTMLAnchorElement)) throw new Error(hasWanted ? `Flow project not found: ${rawWanted}` : 'No clickable Flow project found'); const url = pick.href || pick.getAttribute('href'); if (!url) throw new Error('Project card is missing href'); window.location.assign(url); return url; })()",
33
+ "description": "Open the matching project card",
34
+ "verify": "[role='textbox'][contenteditable='true'][data-slate-editor='true']",
35
+ "verifyTimeoutMs": 15000
36
+ },
37
+ {
38
+ "action": "wait",
39
+ "ms": 800,
40
+ "description": "Allow the project editor to settle"
41
+ },
42
+ {
43
+ "action": "browser_js",
44
+ "code": "(() => { const button = [...document.querySelectorAll('button')].find(el => (el.textContent || '').includes('View images')); if (button instanceof HTMLElement) button.click(); return !!button; })()",
45
+ "description": "Switch the asset rail to images when the filter is present"
46
+ },
47
+ {
48
+ "action": "wait",
49
+ "ms": 400,
50
+ "description": "Wait for the image grid filter to apply"
51
+ },
52
+ {
53
+ "action": "browser_js",
54
+ "code": "(() => { const visible = el => { const r = el.getBoundingClientRect(); const s = getComputedStyle(el); return r.width > 0 && r.height > 0 && s.visibility !== 'hidden' && s.display !== 'none'; }; const rawUrl = `{ASSET_URL}`.trim(); const rawId = `{ASSET_ID}`.trim(); const rawIndex = `{ASSET_INDEX}`.trim(); const wantedIndex = rawIndex && rawIndex !== '{ASSET_INDEX}' ? Number(rawIndex) : 0; const anchors = [...document.querySelectorAll(\"a[href*='/edit/']\")].filter(visible).filter(anchor => { const tile = anchor.closest(\"[id^='fe_id_']\") || anchor.parentElement; return !tile?.querySelector('video'); }); let pick = null; if (rawUrl && rawUrl !== '{ASSET_URL}') pick = anchors.find(anchor => anchor.href === rawUrl); else if (rawId && rawId !== '{ASSET_ID}') pick = anchors.find(anchor => anchor.href.includes(`/edit/${rawId}`) || anchor.closest(`[id='fe_id_${rawId}']`)); else pick = anchors[Math.max(0, wantedIndex)] || anchors[0]; if (!(pick instanceof HTMLAnchorElement)) throw new Error('No Flow image edit link found'); window.location.assign(pick.href); return pick.href; })()",
55
+ "description": "Open the requested image asset in edit view",
56
+ "verify": "[role='textbox'][contenteditable='true'][data-slate-editor='true']",
57
+ "verifyTimeoutMs": 15000
58
+ },
59
+ {
60
+ "action": "wait",
61
+ "ms": 600,
62
+ "description": "Allow the image editor to settle"
63
+ },
64
+ {
65
+ "action": "browser_js",
66
+ "code": "(() => { const modeRaw = `{EDIT_MODE}`.trim().toUpperCase(); const mode = !modeRaw || modeRaw === '{EDIT_MODE}' ? 'PROMPT' : modeRaw; const autoSubmit = `{AUTO_SUBMIT}`.trim() === '1'; const buttonText = { CROP: 'Crop', SELECT: 'Select', DRAW: 'Draw' }; const clickButton = text => { const button = [...document.querySelectorAll('button')].find(el => (el.textContent || '').includes(text)); if (!(button instanceof HTMLElement)) throw new Error(`Flow image tool not found: ${text}`); button.click(); return text; }; let selectedTool = 'PROMPT'; if (buttonText[mode]) selectedTool = clickButton(buttonText[mode]); if (mode === 'CROP') { const aspectRaw = `{CROP_ASPECT}`.trim(); const aspect = !aspectRaw || aspectRaw === '{CROP_ASPECT}' ? '' : aspectRaw; if (aspect) { const aspectButton = [...document.querySelectorAll('button')].find(el => (el.textContent || '').includes(aspect)); if (aspectButton instanceof HTMLElement) aspectButton.click(); } } window.__flowImageEditMode = mode; window.__flowImageEditShouldSubmit = mode === 'PROMPT' || autoSubmit; return JSON.stringify({ mode, selectedTool, shouldSubmit: window.__flowImageEditShouldSubmit }); })()",
67
+ "description": "Choose the image edit mode and stage any tool-specific UI"
68
+ },
69
+ {
70
+ "action": "browser_js",
71
+ "code": "(() => { if (!window.__flowImageEditShouldSubmit) return JSON.stringify({ skipped: true, reason: 'staged_only' }); const prompt = `{PROMPT_TEXT}`.trim(); if (!prompt || prompt === '{PROMPT_TEXT}') throw new Error('PROMPT_TEXT variable is required for image edit submission'); const editorEl = document.querySelector(\"[role='textbox'][contenteditable='true'][data-slate-editor='true']\"); if (!(editorEl instanceof HTMLElement)) throw new Error('Flow image edit prompt box not found'); const fiberKey = Object.keys(editorEl).find(k => k.startsWith('__reactFiber')); let cur = fiberKey ? editorEl[fiberKey] : null; let store = null; for (let i = 0; cur && i < 9; i++, cur = cur.return) { if (i === 7) { store = cur.memoizedProps?.promptBoxStore; break; } } const state = store?.getState?.(); const actions = state?.actions; const textEditor = state?.inputs?.textEditor; if (!actions || !textEditor) throw new Error('Flow image edit store not found'); if (typeof actions.setMode === 'function') actions.setMode('IMAGE'); const currentText = textEditor.children?.[0]?.children?.[0]?.text ?? ''; try { textEditor.select({ anchor: { path: [0, 0], offset: 0 }, focus: { path: [0, 0], offset: currentText.length } }); } catch {} try { textEditor.deleteFragment(); } catch {} textEditor.insertText(prompt); try { textEditor.onChange(); } catch {} const text = (textEditor.children || []).map(node => (node.children || []).map(child => child.text || '').join('')).join('\\n'); window.__flowImageEditPrompt = text; return JSON.stringify({ prompt: text, mode: store.getState().mode, editMode: window.__flowImageEditMode || 'PROMPT' }); })()",
72
+ "description": "Insert the image edit prompt through Flow's internal Slate editor"
73
+ },
74
+ {
75
+ "action": "browser_js",
76
+ "code": "(() => { if (!window.__flowImageEditShouldSubmit) return JSON.stringify({ submitted: false, reason: 'staged_only' }); const submitButton = [...document.querySelectorAll('button')].find(el => (el.textContent || '').includes('arrow_forward') && (el.textContent || '').includes('Create')); if (!(submitButton instanceof HTMLElement)) throw new Error('Flow image edit submit button not found'); const fiberKey = Object.keys(submitButton).find(k => k.startsWith('__reactFiber')); let cur = fiberKey ? submitButton[fiberKey] : null; let onSubmit = null; for (let i = 0; cur && i < 6; i++, cur = cur.return) { if (i === 5) { onSubmit = cur.memoizedProps?.onSubmit; break; } } if (typeof onSubmit !== 'function') throw new Error('Flow image edit onSubmit handler not found'); window.__flowImageEditBaseline = { resourceCount: performance.getEntriesByType('resource').length }; onSubmit(); return JSON.stringify({ submitted: true, baseline: window.__flowImageEditBaseline }); })()",
77
+ "description": "Submit the image edit through Flow's internal handler"
78
+ },
79
+ {
80
+ "action": "browser_js",
81
+ "code": "(() => { if (!window.__flowImageEditShouldSubmit) return JSON.stringify({ staged: true }); const baseline = window.__flowImageEditBaseline || { resourceCount: 0 }; const seenRequest = () => performance.getEntriesByType('resource').slice(baseline.resourceCount).some(entry => /flowMedia:batchGenerateImages|flowWorkflows\\//.test(entry.name)); const start = Date.now(); return new Promise(resolve => { const check = () => { if (seenRequest()) { resolve(JSON.stringify({ submitted: true, generationRequestSeen: true })); return; } if (Date.now() - start > 30000) { resolve(JSON.stringify({ submitted: false, generationRequestSeen: false })); return; } setTimeout(check, 1000); }; check(); }); })()",
82
+ "description": "Wait for Flow to issue the image edit request"
83
+ },
84
+ {
85
+ "action": "screenshot",
86
+ "description": "Capture the image editor after staging or submission",
87
+ "optional": true
88
+ }
89
+ ]
90
+ }