@mseep/clawdcursor 1.5.5
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.
- package/CHANGELOG.md +2264 -0
- package/LICENSE +21 -0
- package/README.md +385 -0
- package/SECURITY.md +44 -0
- package/SKILL.md +503 -0
- package/dist/core/agent-loop/agent.d.ts +42 -0
- package/dist/core/agent-loop/agent.js +1023 -0
- package/dist/core/agent-loop/agent.js.map +1 -0
- package/dist/core/agent-loop/batch-tool.d.ts +25 -0
- package/dist/core/agent-loop/batch-tool.js +218 -0
- package/dist/core/agent-loop/batch-tool.js.map +1 -0
- package/dist/core/agent-loop/coord-scale.d.ts +72 -0
- package/dist/core/agent-loop/coord-scale.js +89 -0
- package/dist/core/agent-loop/coord-scale.js.map +1 -0
- package/dist/core/agent-loop/focus-guard.d.ts +24 -0
- package/dist/core/agent-loop/focus-guard.js +29 -0
- package/dist/core/agent-loop/focus-guard.js.map +1 -0
- package/dist/core/agent-loop/project-mcp.d.ts +97 -0
- package/dist/core/agent-loop/project-mcp.js +253 -0
- package/dist/core/agent-loop/project-mcp.js.map +1 -0
- package/dist/core/agent-loop/prompt.d.ts +45 -0
- package/dist/core/agent-loop/prompt.js +426 -0
- package/dist/core/agent-loop/prompt.js.map +1 -0
- package/dist/core/agent-loop/tool-meta.d.ts +93 -0
- package/dist/core/agent-loop/tool-meta.js +651 -0
- package/dist/core/agent-loop/tool-meta.js.map +1 -0
- package/dist/core/agent-loop/tools.d.ts +38 -0
- package/dist/core/agent-loop/tools.js +2134 -0
- package/dist/core/agent-loop/tools.js.map +1 -0
- package/dist/core/agent-loop/types.d.ts +170 -0
- package/dist/core/agent-loop/types.js +12 -0
- package/dist/core/agent-loop/types.js.map +1 -0
- package/dist/core/agent.d.ts +51 -0
- package/dist/core/agent.js +245 -0
- package/dist/core/agent.js.map +1 -0
- package/dist/core/app-categories.d.ts +67 -0
- package/dist/core/app-categories.js +108 -0
- package/dist/core/app-categories.js.map +1 -0
- package/dist/core/banner.d.ts +70 -0
- package/dist/core/banner.js +245 -0
- package/dist/core/banner.js.map +1 -0
- package/dist/core/classify/capability.d.ts +45 -0
- package/dist/core/classify/capability.js +78 -0
- package/dist/core/classify/capability.js.map +1 -0
- package/dist/core/decompose/llm-decomposer.d.ts +35 -0
- package/dist/core/decompose/llm-decomposer.js +156 -0
- package/dist/core/decompose/llm-decomposer.js.map +1 -0
- package/dist/core/decompose/parser.d.ts +27 -0
- package/dist/core/decompose/parser.js +101 -0
- package/dist/core/decompose/parser.js.map +1 -0
- package/dist/core/observability/correlation.d.ts +19 -0
- package/dist/core/observability/correlation.js +36 -0
- package/dist/core/observability/correlation.js.map +1 -0
- package/dist/core/observability/cost-meter.d.ts +51 -0
- package/dist/core/observability/cost-meter.js +134 -0
- package/dist/core/observability/cost-meter.js.map +1 -0
- package/dist/core/observability/logger.d.ts +61 -0
- package/dist/core/observability/logger.js +550 -0
- package/dist/core/observability/logger.js.map +1 -0
- package/dist/core/router/aliases.d.ts +50 -0
- package/dist/core/router/aliases.js +104 -0
- package/dist/core/router/aliases.js.map +1 -0
- package/dist/core/router/normalize.d.ts +41 -0
- package/dist/core/router/normalize.js +80 -0
- package/dist/core/router/normalize.js.map +1 -0
- package/dist/core/safety.d.ts +126 -0
- package/dist/core/safety.js +568 -0
- package/dist/core/safety.js.map +1 -0
- package/dist/core/sense/a11y-resolver.d.ts +73 -0
- package/dist/core/sense/a11y-resolver.js +76 -0
- package/dist/core/sense/a11y-resolver.js.map +1 -0
- package/dist/core/sense/fingerprint.d.ts +41 -0
- package/dist/core/sense/fingerprint.js +123 -0
- package/dist/core/sense/fingerprint.js.map +1 -0
- package/dist/core/sense/rank.d.ts +70 -0
- package/dist/core/sense/rank.js +192 -0
- package/dist/core/sense/rank.js.map +1 -0
- package/dist/core/sense/reactive-check.d.ts +40 -0
- package/dist/core/sense/reactive-check.js +48 -0
- package/dist/core/sense/reactive-check.js.map +1 -0
- package/dist/core/sense/snapshot.d.ts +19 -0
- package/dist/core/sense/snapshot.js +100 -0
- package/dist/core/sense/snapshot.js.map +1 -0
- package/dist/core/sense/types.d.ts +66 -0
- package/dist/core/sense/types.js +9 -0
- package/dist/core/sense/types.js.map +1 -0
- package/dist/core/sense/ui-map-anchors.d.ts +7 -0
- package/dist/core/sense/ui-map-anchors.js +24 -0
- package/dist/core/sense/ui-map-anchors.js.map +1 -0
- package/dist/core/sense/ui-map-elements.d.ts +5 -0
- package/dist/core/sense/ui-map-elements.js +33 -0
- package/dist/core/sense/ui-map-elements.js.map +1 -0
- package/dist/core/sense/ui-map-find.d.ts +56 -0
- package/dist/core/sense/ui-map-find.js +153 -0
- package/dist/core/sense/ui-map-find.js.map +1 -0
- package/dist/core/sense/ui-map-fuse.d.ts +4 -0
- package/dist/core/sense/ui-map-fuse.js +44 -0
- package/dist/core/sense/ui-map-fuse.js.map +1 -0
- package/dist/core/sense/ui-map-geom.d.ts +3 -0
- package/dist/core/sense/ui-map-geom.js +16 -0
- package/dist/core/sense/ui-map-geom.js.map +1 -0
- package/dist/core/sense/ui-map-holder.d.ts +58 -0
- package/dist/core/sense/ui-map-holder.js +87 -0
- package/dist/core/sense/ui-map-holder.js.map +1 -0
- package/dist/core/sense/ui-map-normalize.d.ts +19 -0
- package/dist/core/sense/ui-map-normalize.js +65 -0
- package/dist/core/sense/ui-map-normalize.js.map +1 -0
- package/dist/core/sense/ui-map-render.d.ts +4 -0
- package/dist/core/sense/ui-map-render.js +34 -0
- package/dist/core/sense/ui-map-render.js.map +1 -0
- package/dist/core/sense/ui-map-resolve.d.ts +41 -0
- package/dist/core/sense/ui-map-resolve.js +59 -0
- package/dist/core/sense/ui-map-resolve.js.map +1 -0
- package/dist/core/sense/ui-map-types.d.ts +66 -0
- package/dist/core/sense/ui-map-types.js +11 -0
- package/dist/core/sense/ui-map-types.js.map +1 -0
- package/dist/core/sense/ui-map.d.ts +29 -0
- package/dist/core/sense/ui-map.js +113 -0
- package/dist/core/sense/ui-map.js.map +1 -0
- package/dist/core/verify/assertions.d.ts +132 -0
- package/dist/core/verify/assertions.js +284 -0
- package/dist/core/verify/assertions.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/browser-config.d.ts +36 -0
- package/dist/llm/browser-config.js +83 -0
- package/dist/llm/browser-config.js.map +1 -0
- package/dist/llm/client.d.ts +268 -0
- package/dist/llm/client.js +1094 -0
- package/dist/llm/client.js.map +1 -0
- package/dist/llm/config.d.ts +79 -0
- package/dist/llm/config.js +375 -0
- package/dist/llm/config.js.map +1 -0
- package/dist/llm/credentials.d.ts +35 -0
- package/dist/llm/credentials.js +491 -0
- package/dist/llm/credentials.js.map +1 -0
- package/dist/llm/external-creds.d.ts +42 -0
- package/dist/llm/external-creds.js +169 -0
- package/dist/llm/external-creds.js.map +1 -0
- package/dist/llm/providers.d.ts +123 -0
- package/dist/llm/providers.js +717 -0
- package/dist/llm/providers.js.map +1 -0
- package/dist/paths.d.ts +31 -0
- package/dist/paths.js +147 -0
- package/dist/paths.js.map +1 -0
- package/dist/platform/accessibility.d.ts +139 -0
- package/dist/platform/accessibility.js +670 -0
- package/dist/platform/accessibility.js.map +1 -0
- package/dist/platform/cdp-driver.d.ts +318 -0
- package/dist/platform/cdp-driver.js +1179 -0
- package/dist/platform/cdp-driver.js.map +1 -0
- package/dist/platform/index.d.ts +11 -0
- package/dist/platform/index.js +69 -0
- package/dist/platform/index.js.map +1 -0
- package/dist/platform/keys.d.ts +17 -0
- package/dist/platform/keys.js +129 -0
- package/dist/platform/keys.js.map +1 -0
- package/dist/platform/launch-poll.d.ts +101 -0
- package/dist/platform/launch-poll.js +177 -0
- package/dist/platform/launch-poll.js.map +1 -0
- package/dist/platform/linux.d.ts +173 -0
- package/dist/platform/linux.js +1253 -0
- package/dist/platform/linux.js.map +1 -0
- package/dist/platform/macos.d.ts +136 -0
- package/dist/platform/macos.js +976 -0
- package/dist/platform/macos.js.map +1 -0
- package/dist/platform/native-desktop.d.ts +145 -0
- package/dist/platform/native-desktop.js +936 -0
- package/dist/platform/native-desktop.js.map +1 -0
- package/dist/platform/native-helper.d.ts +130 -0
- package/dist/platform/native-helper.js +592 -0
- package/dist/platform/native-helper.js.map +1 -0
- package/dist/platform/ocr-engine.d.ts +78 -0
- package/dist/platform/ocr-engine.js +363 -0
- package/dist/platform/ocr-engine.js.map +1 -0
- package/dist/platform/ps-runner.d.ts +28 -0
- package/dist/platform/ps-runner.js +228 -0
- package/dist/platform/ps-runner.js.map +1 -0
- package/dist/platform/types.d.ts +397 -0
- package/dist/platform/types.js +15 -0
- package/dist/platform/types.js.map +1 -0
- package/dist/platform/uri-handler.d.ts +75 -0
- package/dist/platform/uri-handler.js +273 -0
- package/dist/platform/uri-handler.js.map +1 -0
- package/dist/platform/wayland-backend.d.ts +53 -0
- package/dist/platform/wayland-backend.js +348 -0
- package/dist/platform/wayland-backend.js.map +1 -0
- package/dist/platform/windows.d.ts +232 -0
- package/dist/platform/windows.js +1210 -0
- package/dist/platform/windows.js.map +1 -0
- package/dist/postbuild.d.ts +10 -0
- package/dist/postbuild.js +98 -0
- package/dist/postbuild.js.map +1 -0
- package/dist/schema/snapshot.d.ts +33 -0
- package/dist/schema/snapshot.js +90 -0
- package/dist/schema/snapshot.js.map +1 -0
- package/dist/shortcuts.d.ts +30 -0
- package/dist/shortcuts.js +261 -0
- package/dist/shortcuts.js.map +1 -0
- package/dist/surface/cli.d.ts +7 -0
- package/dist/surface/cli.js +1556 -0
- package/dist/surface/cli.js.map +1 -0
- package/dist/surface/dashboard.d.ts +8 -0
- package/dist/surface/dashboard.js +1193 -0
- package/dist/surface/dashboard.js.map +1 -0
- package/dist/surface/doctor.d.ts +29 -0
- package/dist/surface/doctor.js +1514 -0
- package/dist/surface/doctor.js.map +1 -0
- package/dist/surface/format.d.ts +10 -0
- package/dist/surface/format.js +37 -0
- package/dist/surface/format.js.map +1 -0
- package/dist/surface/http-utility.d.ts +65 -0
- package/dist/surface/http-utility.js +336 -0
- package/dist/surface/http-utility.js.map +1 -0
- package/dist/surface/mcp-server.d.ts +91 -0
- package/dist/surface/mcp-server.js +280 -0
- package/dist/surface/mcp-server.js.map +1 -0
- package/dist/surface/onboarding.d.ts +15 -0
- package/dist/surface/onboarding.js +184 -0
- package/dist/surface/onboarding.js.map +1 -0
- package/dist/surface/pidfile.d.ts +79 -0
- package/dist/surface/pidfile.js +263 -0
- package/dist/surface/pidfile.js.map +1 -0
- package/dist/surface/readiness.d.ts +45 -0
- package/dist/surface/readiness.js +230 -0
- package/dist/surface/readiness.js.map +1 -0
- package/dist/surface/report.d.ts +68 -0
- package/dist/surface/report.js +341 -0
- package/dist/surface/report.js.map +1 -0
- package/dist/surface/skill-register.d.ts +14 -0
- package/dist/surface/skill-register.js +150 -0
- package/dist/surface/skill-register.js.map +1 -0
- package/dist/surface/version.d.ts +6 -0
- package/dist/surface/version.js +27 -0
- package/dist/surface/version.js.map +1 -0
- package/dist/tools/a11y.d.ts +8 -0
- package/dist/tools/a11y.js +545 -0
- package/dist/tools/a11y.js.map +1 -0
- package/dist/tools/a11y_depth.d.ts +19 -0
- package/dist/tools/a11y_depth.js +455 -0
- package/dist/tools/a11y_depth.js.map +1 -0
- package/dist/tools/agent.d.ts +15 -0
- package/dist/tools/agent.js +248 -0
- package/dist/tools/agent.js.map +1 -0
- package/dist/tools/batch.d.ts +46 -0
- package/dist/tools/batch.js +230 -0
- package/dist/tools/batch.js.map +1 -0
- package/dist/tools/cdp.d.ts +8 -0
- package/dist/tools/cdp.js +233 -0
- package/dist/tools/cdp.js.map +1 -0
- package/dist/tools/compact.d.ts +63 -0
- package/dist/tools/compact.js +418 -0
- package/dist/tools/compact.js.map +1 -0
- package/dist/tools/cost-class.d.ts +38 -0
- package/dist/tools/cost-class.js +117 -0
- package/dist/tools/cost-class.js.map +1 -0
- package/dist/tools/desktop.d.ts +9 -0
- package/dist/tools/desktop.js +346 -0
- package/dist/tools/desktop.js.map +1 -0
- package/dist/tools/electron_bridge.d.ts +41 -0
- package/dist/tools/electron_bridge.js +261 -0
- package/dist/tools/electron_bridge.js.map +1 -0
- package/dist/tools/extras.d.ts +22 -0
- package/dist/tools/extras.js +942 -0
- package/dist/tools/extras.js.map +1 -0
- package/dist/tools/favorites.d.ts +13 -0
- package/dist/tools/favorites.js +137 -0
- package/dist/tools/favorites.js.map +1 -0
- package/dist/tools/introspection.d.ts +13 -0
- package/dist/tools/introspection.js +55 -0
- package/dist/tools/introspection.js.map +1 -0
- package/dist/tools/ocr.d.ts +8 -0
- package/dist/tools/ocr.js +66 -0
- package/dist/tools/ocr.js.map +1 -0
- package/dist/tools/orchestration.d.ts +7 -0
- package/dist/tools/orchestration.js +377 -0
- package/dist/tools/orchestration.js.map +1 -0
- package/dist/tools/playbooks/extract-compose.d.ts +22 -0
- package/dist/tools/playbooks/extract-compose.js +85 -0
- package/dist/tools/playbooks/extract-compose.js.map +1 -0
- package/dist/tools/playbooks/find-replace.d.ts +11 -0
- package/dist/tools/playbooks/find-replace.js +56 -0
- package/dist/tools/playbooks/find-replace.js.map +1 -0
- package/dist/tools/playbooks/index.d.ts +63 -0
- package/dist/tools/playbooks/index.js +70 -0
- package/dist/tools/playbooks/index.js.map +1 -0
- package/dist/tools/playbooks/keys-blocklist.d.ts +24 -0
- package/dist/tools/playbooks/keys-blocklist.js +89 -0
- package/dist/tools/playbooks/keys-blocklist.js.map +1 -0
- package/dist/tools/registry.d.ts +40 -0
- package/dist/tools/registry.js +560 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/safety-gate.d.ts +16 -0
- package/dist/tools/safety-gate.js +70 -0
- package/dist/tools/safety-gate.js.map +1 -0
- package/dist/tools/scheduler.d.ts +76 -0
- package/dist/tools/scheduler.js +413 -0
- package/dist/tools/scheduler.js.map +1 -0
- package/dist/tools/shortcuts.d.ts +13 -0
- package/dist/tools/shortcuts.js +205 -0
- package/dist/tools/shortcuts.js.map +1 -0
- package/dist/tools/smart.d.ts +15 -0
- package/dist/tools/smart.js +785 -0
- package/dist/tools/smart.js.map +1 -0
- package/dist/tools/types.d.ts +174 -0
- package/dist/tools/types.js +67 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/window-text.d.ts +15 -0
- package/dist/tools/window-text.js +39 -0
- package/dist/tools/window-text.js.map +1 -0
- package/dist/types.d.ts +122 -0
- package/dist/types.js +41 -0
- package/dist/types.js.map +1 -0
- package/native/Package.swift +38 -0
- package/native/README.md +113 -0
- package/native/Sources/ClawdCursorHelper/main.swift +602 -0
- package/native/Sources/ClawdCursorHost/main.swift +182 -0
- package/native/Sources/PermissionCheck/main.swift +53 -0
- package/native/Sources/ScreenshotHelper/main.swift +219 -0
- package/native/build.sh +139 -0
- package/native/entitlements.plist +12 -0
- package/package.json +115 -0
- package/scripts/banner.ps1 +112 -0
- package/scripts/coord-accuracy.ps1 +140 -0
- package/scripts/coord-uwp.ps1 +80 -0
- package/scripts/edge-glow.ps1 +180 -0
- package/scripts/find-element.ps1 +198 -0
- package/scripts/get-foreground-window.ps1 +71 -0
- package/scripts/get-screen-context.ps1 +183 -0
- package/scripts/get-windows.ps1 +66 -0
- package/scripts/install-panic-hotkey.ps1 +46 -0
- package/scripts/interact-element.ps1 +431 -0
- package/scripts/invoke-element.ps1 +314 -0
- package/scripts/linux/atspi-bridge.py +356 -0
- package/scripts/linux/ocr-recognize.py +154 -0
- package/scripts/mac/_window-picker.jxa +163 -0
- package/scripts/mac/find-element.jxa +0 -0
- package/scripts/mac/find-element.sh +161 -0
- package/scripts/mac/focus-window.jxa +284 -0
- package/scripts/mac/get-focused-element.jxa +102 -0
- package/scripts/mac/get-foreground-window.jxa +173 -0
- package/scripts/mac/get-screen-context.jxa +197 -0
- package/scripts/mac/get-ui-tree.sh +141 -0
- package/scripts/mac/get-windows.jxa +117 -0
- package/scripts/mac/interact-element.sh +235 -0
- package/scripts/mac/invoke-element.jxa +408 -0
- package/scripts/mac/ocr-recognize.swift +124 -0
- package/scripts/ocr-recognize.ps1 +102 -0
- package/scripts/postinstall-native.js +48 -0
- package/scripts/ps-bridge.ps1 +830 -0
- package/scripts/smoke-mcp.ps1 +119 -0
- package/scripts/sync-version.ts +178 -0
- package/scripts/verify-install.js +81 -0
package/package.json
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mseep/clawdcursor",
|
|
3
|
+
"version": "1.5.5",
|
|
4
|
+
"mcpName": "io.github.AmrDab/clawdcursor",
|
|
5
|
+
"description": "Local MCP server that gives any AI agent safe cross-OS desktop control \u2014 the fallback execution layer for when APIs, CLIs, and direct integrations aren't available. Works with any tool-calling model (Claude, GPT, Gemini, Llama) on Windows, macOS, and Linux. Open source (MIT).",
|
|
6
|
+
"homepage": "https://clawdcursor.com",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/AmrDab/clawdcursor.git"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/AmrDab/clawdcursor/issues"
|
|
13
|
+
},
|
|
14
|
+
"author": "Amr Dabbas",
|
|
15
|
+
"keywords": [
|
|
16
|
+
"agent",
|
|
17
|
+
"ai-agent",
|
|
18
|
+
"mcp",
|
|
19
|
+
"mcp-server",
|
|
20
|
+
"model-context-protocol",
|
|
21
|
+
"desktop-automation",
|
|
22
|
+
"computer-use",
|
|
23
|
+
"gui-automation",
|
|
24
|
+
"accessibility",
|
|
25
|
+
"claude",
|
|
26
|
+
"gpt",
|
|
27
|
+
"openai",
|
|
28
|
+
"anthropic",
|
|
29
|
+
"skill",
|
|
30
|
+
"cli",
|
|
31
|
+
"mseep"
|
|
32
|
+
],
|
|
33
|
+
"bin": {
|
|
34
|
+
"clawdcursor": "dist/surface/cli.js"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist/",
|
|
38
|
+
"scripts/verify-install.js",
|
|
39
|
+
"scripts/postinstall-native.js",
|
|
40
|
+
"scripts/sync-version.ts",
|
|
41
|
+
"scripts/*.ps1",
|
|
42
|
+
"scripts/mac/",
|
|
43
|
+
"scripts/linux/",
|
|
44
|
+
"native/build.sh",
|
|
45
|
+
"native/Package.swift",
|
|
46
|
+
"native/Sources/",
|
|
47
|
+
"native/entitlements.plist",
|
|
48
|
+
"README.md",
|
|
49
|
+
"LICENSE",
|
|
50
|
+
"CHANGELOG.md",
|
|
51
|
+
"SECURITY.md",
|
|
52
|
+
"SKILL.md"
|
|
53
|
+
],
|
|
54
|
+
"scripts": {
|
|
55
|
+
"postinstall": "node scripts/verify-install.js || node -e \"process.exit(0)\" && node scripts/postinstall-native.js || node -e \"process.exit(0)\"",
|
|
56
|
+
"clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
57
|
+
"prepare": "npm run clean && tsc && node dist/postbuild.js",
|
|
58
|
+
"prebuild": "npm run clean",
|
|
59
|
+
"build": "tsc && node dist/postbuild.js",
|
|
60
|
+
"setup": "node scripts/verify-install.js && npm run build && node -e \"if(process.platform==='darwin'){const{execSync}=require('child_process');try{execSync('chmod +x native/build.sh && native/build.sh',{stdio:'inherit'})}catch(e){console.error('\\n\u274c Native build failed. Run manually: cd native && ./build.sh');process.exit(1)}}\" && npm link --force",
|
|
61
|
+
"postbuild:msg": "handled by postbuild.js",
|
|
62
|
+
"dev": "tsx watch src/surface/cli.ts",
|
|
63
|
+
"start": "node dist/surface/cli.js agent",
|
|
64
|
+
"stop": "node dist/surface/cli.js stop",
|
|
65
|
+
"doctor": "node dist/surface/cli.js doctor",
|
|
66
|
+
"lint": "eslint src/",
|
|
67
|
+
"test": "vitest",
|
|
68
|
+
"test:ci": "vitest run",
|
|
69
|
+
"test:mcp-schema-snapshot": "tsx scripts/build-mcp-schema.ts",
|
|
70
|
+
"test:mcp-schema-snapshot:update": "tsx scripts/build-mcp-schema.ts --write",
|
|
71
|
+
"typecheck": "tsc --noEmit",
|
|
72
|
+
"typecheck:tests": "tsc --noEmit -p tsconfig.tests.json",
|
|
73
|
+
"sync-version": "tsx scripts/sync-version.ts",
|
|
74
|
+
"version": "tsx scripts/sync-version.ts && git add SKILL.md docs/index.html docs/install.sh docs/install.ps1",
|
|
75
|
+
"test:coverage": "vitest run --coverage",
|
|
76
|
+
"perf:smoke": "tsx scripts/perf-smoke.ts"
|
|
77
|
+
},
|
|
78
|
+
"dependencies": {
|
|
79
|
+
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
80
|
+
"@nut-tree-fork/nut-js": "^4.2.0",
|
|
81
|
+
"commander": "^15.0.0",
|
|
82
|
+
"croner": "^10.0.1",
|
|
83
|
+
"dotenv": "^17.4.2",
|
|
84
|
+
"express": "^5.2.1",
|
|
85
|
+
"picocolors": "^1.1.1",
|
|
86
|
+
"playwright": "^1.60.0",
|
|
87
|
+
"sharp": "^0.34.5",
|
|
88
|
+
"ws": "^8.21.0",
|
|
89
|
+
"zod": "^4.4.3"
|
|
90
|
+
},
|
|
91
|
+
"devDependencies": {
|
|
92
|
+
"@eslint/js": "^10.0.1",
|
|
93
|
+
"@types/express": "^5.0.6",
|
|
94
|
+
"@types/node": "^25.9.2",
|
|
95
|
+
"@types/supertest": "^7.2.0",
|
|
96
|
+
"@types/ws": "^8.5.0",
|
|
97
|
+
"@typescript-eslint/eslint-plugin": "^8.60.1",
|
|
98
|
+
"@typescript-eslint/parser": "^8.60.1",
|
|
99
|
+
"@vitest/coverage-v8": "^4.1.8",
|
|
100
|
+
"eslint": "^10.4.1",
|
|
101
|
+
"supertest": "^7.2.2",
|
|
102
|
+
"tsx": "^4.22.4",
|
|
103
|
+
"typescript": "^6.0.3",
|
|
104
|
+
"vitest": "^4.1.8"
|
|
105
|
+
},
|
|
106
|
+
"overrides": {
|
|
107
|
+
"ip-address": "10.1.1",
|
|
108
|
+
"brace-expansion": "5.0.6"
|
|
109
|
+
},
|
|
110
|
+
"engines": {
|
|
111
|
+
"node": ">=20.0.0"
|
|
112
|
+
},
|
|
113
|
+
"license": "MIT",
|
|
114
|
+
"publisher": "mseep"
|
|
115
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# banner.ps1 — "ClawdCursor — desktop control in progress" indicator.
|
|
2
|
+
#
|
|
3
|
+
# A small, always-on-top, borderless pill at the top-center of the primary
|
|
4
|
+
# screen with a blinking red "recording" dot. Shown by the daemon while an
|
|
5
|
+
# agent is actively driving the desktop, so a human at the machine ALWAYS
|
|
6
|
+
# knows automation is live (transparency requirement — same spirit as the
|
|
7
|
+
# labeled agent browser window).
|
|
8
|
+
#
|
|
9
|
+
# Interaction contract with the parent (src/core/banner.ts):
|
|
10
|
+
# - Parent spawns: powershell -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File banner.ps1
|
|
11
|
+
# - DOUBLE-CLICK anywhere on the banner → prints "BANNER_STOP" on stdout and
|
|
12
|
+
# exits; the parent reacts by running the `clawdcursor stop` flow
|
|
13
|
+
# (abort in-flight task + graceful daemon shutdown).
|
|
14
|
+
# - Parent kills this process to hide the banner.
|
|
15
|
+
#
|
|
16
|
+
# CRITICAL: the window must NEVER steal focus — it appears WHILE the agent is
|
|
17
|
+
# typing/clicking, and an activating window would redirect those keystrokes
|
|
18
|
+
# (the exact focus-theft bug class fixed in v1.5.1). WS_EX_NOACTIVATE +
|
|
19
|
+
# ShowWithoutActivation make it a zero-focus overlay; clicks still reach it.
|
|
20
|
+
|
|
21
|
+
$ErrorActionPreference = 'Stop'
|
|
22
|
+
Add-Type -AssemblyName System.Windows.Forms
|
|
23
|
+
Add-Type -AssemblyName System.Drawing
|
|
24
|
+
|
|
25
|
+
Add-Type -ReferencedAssemblies System.Windows.Forms, System.Drawing -TypeDefinition @'
|
|
26
|
+
using System;
|
|
27
|
+
using System.Windows.Forms;
|
|
28
|
+
|
|
29
|
+
public class NoActivateBannerForm : Form {
|
|
30
|
+
// Never take focus when shown…
|
|
31
|
+
protected override bool ShowWithoutActivation { get { return true; } }
|
|
32
|
+
// …or when clicked. WS_EX_NOACTIVATE (0x08000000) + WS_EX_TOPMOST (0x8).
|
|
33
|
+
protected override CreateParams CreateParams {
|
|
34
|
+
get {
|
|
35
|
+
CreateParams p = base.CreateParams;
|
|
36
|
+
p.ExStyle |= 0x08000000; // WS_EX_NOACTIVATE
|
|
37
|
+
p.ExStyle |= 0x00000008; // WS_EX_TOPMOST
|
|
38
|
+
return p;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
'@
|
|
43
|
+
|
|
44
|
+
$form = New-Object NoActivateBannerForm
|
|
45
|
+
$form.FormBorderStyle = 'None'
|
|
46
|
+
$form.ShowInTaskbar = $false
|
|
47
|
+
$form.TopMost = $true
|
|
48
|
+
$form.StartPosition = 'Manual'
|
|
49
|
+
$form.BackColor = [System.Drawing.Color]::FromArgb(18, 18, 26)
|
|
50
|
+
$form.Size = New-Object System.Drawing.Size(430, 40)
|
|
51
|
+
|
|
52
|
+
# Top-center of the primary screen, 8px below the edge.
|
|
53
|
+
$screen = [System.Windows.Forms.Screen]::PrimaryScreen.WorkingArea
|
|
54
|
+
$form.Location = New-Object System.Drawing.Point(
|
|
55
|
+
[int]($screen.X + ($screen.Width - $form.Width) / 2), [int]($screen.Y + 8))
|
|
56
|
+
|
|
57
|
+
# Rounded pill region.
|
|
58
|
+
$gp = New-Object System.Drawing.Drawing2D.GraphicsPath
|
|
59
|
+
$r = 18; $w = $form.Width; $h = $form.Height
|
|
60
|
+
$gp.AddArc(0, 0, $r*2, $r*2, 180, 90)
|
|
61
|
+
$gp.AddArc($w - $r*2, 0, $r*2, $r*2, 270, 90)
|
|
62
|
+
$gp.AddArc($w - $r*2, $h - $r*2, $r*2, $r*2, 0, 90)
|
|
63
|
+
$gp.AddArc(0, $h - $r*2, $r*2, $r*2, 90, 90)
|
|
64
|
+
$gp.CloseFigure()
|
|
65
|
+
$form.Region = New-Object System.Drawing.Region($gp)
|
|
66
|
+
|
|
67
|
+
$dot = New-Object System.Windows.Forms.Label
|
|
68
|
+
$dot.Text = [char]0x25CF # ●
|
|
69
|
+
$dot.Font = New-Object System.Drawing.Font('Segoe UI', 14, [System.Drawing.FontStyle]::Bold)
|
|
70
|
+
$dot.ForeColor = [System.Drawing.Color]::FromArgb(255, 59, 48)
|
|
71
|
+
$dot.BackColor = [System.Drawing.Color]::Transparent
|
|
72
|
+
$dot.AutoSize = $true
|
|
73
|
+
$dot.Location = New-Object System.Drawing.Point(14, 5)
|
|
74
|
+
|
|
75
|
+
$text = New-Object System.Windows.Forms.Label
|
|
76
|
+
$text.Text = 'ClawdCursor ' # brand
|
|
77
|
+
$text.Font = New-Object System.Drawing.Font('Segoe UI Semibold', 10)
|
|
78
|
+
$text.ForeColor = [System.Drawing.Color]::White
|
|
79
|
+
$text.BackColor = [System.Drawing.Color]::Transparent
|
|
80
|
+
$text.AutoSize = $true
|
|
81
|
+
$text.Location = New-Object System.Drawing.Point(40, 10)
|
|
82
|
+
|
|
83
|
+
$sub = New-Object System.Windows.Forms.Label
|
|
84
|
+
$sub.Text = 'desktop control in progress - double-click to stop'
|
|
85
|
+
$sub.Font = New-Object System.Drawing.Font('Segoe UI', 9)
|
|
86
|
+
$sub.ForeColor = [System.Drawing.Color]::FromArgb(170, 170, 185)
|
|
87
|
+
$sub.BackColor = [System.Drawing.Color]::Transparent
|
|
88
|
+
$sub.AutoSize = $true
|
|
89
|
+
$sub.Location = New-Object System.Drawing.Point(133, 11)
|
|
90
|
+
|
|
91
|
+
$form.Controls.AddRange(@($dot, $text, $sub))
|
|
92
|
+
|
|
93
|
+
# Recording blink — bright/dim every 600ms.
|
|
94
|
+
$timer = New-Object System.Windows.Forms.Timer
|
|
95
|
+
$timer.Interval = 600
|
|
96
|
+
$bright = $true
|
|
97
|
+
$timer.Add_Tick({
|
|
98
|
+
$script:bright = -not $script:bright
|
|
99
|
+
if ($script:bright) { $dot.ForeColor = [System.Drawing.Color]::FromArgb(255, 59, 48) }
|
|
100
|
+
else { $dot.ForeColor = [System.Drawing.Color]::FromArgb(110, 25, 20) }
|
|
101
|
+
})
|
|
102
|
+
$timer.Start()
|
|
103
|
+
|
|
104
|
+
$stopHandler = {
|
|
105
|
+
[Console]::Out.WriteLine('BANNER_STOP')
|
|
106
|
+
[Console]::Out.Flush()
|
|
107
|
+
$form.Close()
|
|
108
|
+
}
|
|
109
|
+
$form.Add_MouseDoubleClick($stopHandler)
|
|
110
|
+
foreach ($c in @($dot, $text, $sub)) { $c.Add_MouseDoubleClick($stopHandler) }
|
|
111
|
+
|
|
112
|
+
[System.Windows.Forms.Application]::Run($form)
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Direct-drive coordinate accuracy test against the running daemon.
|
|
2
|
+
# No `clawdcursor agent` loop, no LLM in the path - just MCP tool calls.
|
|
3
|
+
#
|
|
4
|
+
# What it proves:
|
|
5
|
+
# 1. read_screen reports element bounds at logical coords.
|
|
6
|
+
# 2. mouse_click on those coords lands on the element (focus shifts to it).
|
|
7
|
+
# 3. invoke_element clicks the right thing without coord math at all.
|
|
8
|
+
# 4. The values returned by find_element + the get_screen_size scale factor
|
|
9
|
+
# agree end-to-end across DPI.
|
|
10
|
+
|
|
11
|
+
param([int]$Port = 3847)
|
|
12
|
+
|
|
13
|
+
$token = (Get-Content "$env:USERPROFILE\.clawdcursor\token" -Raw).Trim()
|
|
14
|
+
$base = "http://127.0.0.1:$Port/mcp"
|
|
15
|
+
$hdrs = @{
|
|
16
|
+
"Authorization" = "Bearer $token"
|
|
17
|
+
"Accept" = "application/json, text/event-stream"
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function Call-Tool {
|
|
21
|
+
param([string]$Name, [hashtable]$Arguments = @{})
|
|
22
|
+
$body = (@{ jsonrpc="2.0"; id=1; method="tools/call"; params=@{ name=$Name; arguments=$Arguments } } | ConvertTo-Json -Depth 10 -Compress)
|
|
23
|
+
try {
|
|
24
|
+
$r = Invoke-WebRequest -Uri $base -Method POST -Headers $hdrs -ContentType "application/json" -Body $body -UseBasicParsing -TimeoutSec 15
|
|
25
|
+
if ($r.Content -match '(?s)data:\s*(\{.*\})') {
|
|
26
|
+
return ($matches[1] | ConvertFrom-Json)
|
|
27
|
+
}
|
|
28
|
+
return ($r.Content | ConvertFrom-Json)
|
|
29
|
+
} catch { return @{ error = @{ message = $_.Exception.Message } } }
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function Tool-Text {
|
|
33
|
+
param($r)
|
|
34
|
+
if ($r.error) { return "ERROR: $($r.error.message)" }
|
|
35
|
+
if ($r.result.content) { return ($r.result.content | ForEach-Object { $_.text }) -join "`n" }
|
|
36
|
+
return ($r | ConvertTo-Json -Depth 5 -Compress)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
Write-Host ""
|
|
40
|
+
Write-Host "============================================"
|
|
41
|
+
Write-Host " Coordinate accuracy test"
|
|
42
|
+
Write-Host "============================================"
|
|
43
|
+
|
|
44
|
+
# A) Screen / scale baseline
|
|
45
|
+
$ssR = Call-Tool "get_screen_size"
|
|
46
|
+
$ss = Tool-Text $ssR
|
|
47
|
+
Write-Host ""
|
|
48
|
+
Write-Host "[A] get_screen_size:"
|
|
49
|
+
Write-Host " $ss"
|
|
50
|
+
|
|
51
|
+
# B) Open Notepad fresh (clean Win32, no ApplicationFrameHost UWP wrapper)
|
|
52
|
+
$null = Call-Tool "open_app" @{ name = "Notepad" }
|
|
53
|
+
Start-Sleep -Seconds 2
|
|
54
|
+
$null = Call-Tool "focus_window" @{ title = "Notepad" }
|
|
55
|
+
Start-Sleep -Milliseconds 500
|
|
56
|
+
|
|
57
|
+
# C) Read the a11y tree, find the Text editor element bounds
|
|
58
|
+
$treeR = Call-Tool "read_screen"
|
|
59
|
+
$tree = Tool-Text $treeR
|
|
60
|
+
Write-Host ""
|
|
61
|
+
Write-Host "[B] Notepad a11y bounds (look for [Edit] / Text editor lines):"
|
|
62
|
+
$tree -split "`n" | Where-Object { $_ -match "Text editor|Edit|Document" } | Select-Object -First 5 | ForEach-Object { Write-Host " $_" }
|
|
63
|
+
|
|
64
|
+
# Extract the Edit bounds. Format example:
|
|
65
|
+
# [Edit] "Text editor" id:... @122,200 1200x600
|
|
66
|
+
$editLine = ($tree -split "`n") | Where-Object { $_ -match "@\d+,\d+\s+\d+x\d+.*Text editor|Text editor.*@\d+,\d+" } | Select-Object -First 1
|
|
67
|
+
if (-not $editLine) {
|
|
68
|
+
$editLine = ($tree -split "`n") | Where-Object { $_ -match "\[Edit\]" } | Select-Object -First 1
|
|
69
|
+
}
|
|
70
|
+
Write-Host ""
|
|
71
|
+
Write-Host "[C] Picked editor line:"
|
|
72
|
+
Write-Host " $editLine"
|
|
73
|
+
|
|
74
|
+
if ($editLine -match "@(\d+),(\d+)\s+(\d+)x(\d+)") {
|
|
75
|
+
$ex = [int]$matches[1]; $ey = [int]$matches[2]
|
|
76
|
+
$ew = [int]$matches[3]; $eh = [int]$matches[4]
|
|
77
|
+
$cx = $ex + [int]($ew / 2)
|
|
78
|
+
$cy = $ey + [int]($eh / 2)
|
|
79
|
+
Write-Host ""
|
|
80
|
+
Write-Host "[D] Edit center calc: ($cx, $cy) bounds @($ex,$ey) ${ew}x${eh}"
|
|
81
|
+
|
|
82
|
+
# D1) Click via raw coords - verify focus moves to the Edit
|
|
83
|
+
$null = Call-Tool "mouse_click" @{ x = $cx; y = $cy }
|
|
84
|
+
Start-Sleep -Milliseconds 400
|
|
85
|
+
$focusR = Call-Tool "get_focused_element"
|
|
86
|
+
$focus = Tool-Text $focusR
|
|
87
|
+
Write-Host ""
|
|
88
|
+
Write-Host "[E] After mouse_click($cx,$cy) - focused element:"
|
|
89
|
+
Write-Host " $focus"
|
|
90
|
+
$isEditFocused = ($focus -match "Edit|Text editor|Document|RichEdit")
|
|
91
|
+
if ($isEditFocused) {
|
|
92
|
+
Write-Host " PASS raw coordinate click landed in the editor" -ForegroundColor Green
|
|
93
|
+
} else {
|
|
94
|
+
Write-Host " FAIL raw coordinate click did NOT focus the editor" -ForegroundColor Red
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
# D2) Now type a marker - if focus is right, it appears in the doc
|
|
98
|
+
$marker = "COORD_TEST_$([int](Get-Random -Maximum 99999))"
|
|
99
|
+
$null = Call-Tool "type_text" @{ text = $marker }
|
|
100
|
+
Start-Sleep -Milliseconds 400
|
|
101
|
+
$tree2 = Tool-Text (Call-Tool "read_screen")
|
|
102
|
+
$contained = ($tree2 -match [regex]::Escape($marker))
|
|
103
|
+
Write-Host ""
|
|
104
|
+
Write-Host "[F] type_text('$marker') -> tree contains marker: $contained"
|
|
105
|
+
if ($contained) {
|
|
106
|
+
Write-Host " PASS raw click + type was end-to-end correct" -ForegroundColor Green
|
|
107
|
+
} else {
|
|
108
|
+
Write-Host " FAIL marker not found in tree" -ForegroundColor Red
|
|
109
|
+
}
|
|
110
|
+
} else {
|
|
111
|
+
Write-Host " Could not parse bounds from editor line - skipping coord test" -ForegroundColor Yellow
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
# E) Title bar buttons: Minimize sits at a known position on every Win32 window.
|
|
115
|
+
# Use it to test edge-of-window coord accuracy without actually minimizing.
|
|
116
|
+
$minLine = ($tree -split "`n") | Where-Object { $_ -match "\[Button\] `"Minimize" } | Select-Object -First 1
|
|
117
|
+
if ($minLine -match "@(\d+),(\d+)\s+(\d+)x(\d+)") {
|
|
118
|
+
$mx = [int]$matches[1] + [int]([int]$matches[3] / 2)
|
|
119
|
+
$my = [int]$matches[2] + [int]([int]$matches[4] / 2)
|
|
120
|
+
Write-Host ""
|
|
121
|
+
Write-Host "[G] Minimize button center: ($mx, $my) - HOVER ONLY (no click)"
|
|
122
|
+
# Hover, then read the focused window - if hover landed there, the tooltip
|
|
123
|
+
# area would update but the focused element should not (hover != click).
|
|
124
|
+
$null = Call-Tool "mouse_hover" @{ x = $mx; y = $my }
|
|
125
|
+
Start-Sleep -Milliseconds 250
|
|
126
|
+
Write-Host " (hover dispatched; visible verification is the tooltip you may see)"
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
Write-Host ""
|
|
130
|
+
Write-Host "============================================"
|
|
131
|
+
Write-Host " Limitations probed:"
|
|
132
|
+
Write-Host "============================================"
|
|
133
|
+
Write-Host " - DPI scaling: get_screen_size already prints the scaleFactor."
|
|
134
|
+
Write-Host " - UWP offset (Calculator): the wrapped ApplicationFrameHost"
|
|
135
|
+
Write-Host " case is tested separately - this run focuses on plain Win32."
|
|
136
|
+
Write-Host " - Multi-monitor: not exercised here. read_screen reports virtual"
|
|
137
|
+
Write-Host " desktop coords; off-primary-monitor accuracy needs a multi-mon"
|
|
138
|
+
Write-Host " box to validate."
|
|
139
|
+
Write-Host " - Negative coords (left-of-primary monitor): same as above."
|
|
140
|
+
Write-Host ""
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
param([int]$Port = 3847)
|
|
2
|
+
|
|
3
|
+
$token = (Get-Content "$env:USERPROFILE\.clawdcursor\token" -Raw).Trim()
|
|
4
|
+
$base = "http://127.0.0.1:$Port/mcp"
|
|
5
|
+
$hdrs = @{
|
|
6
|
+
"Authorization" = "Bearer $token"
|
|
7
|
+
"Accept" = "application/json, text/event-stream"
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function Call-Tool {
|
|
11
|
+
param([string]$Name, [hashtable]$Arguments = @{})
|
|
12
|
+
$body = (@{ jsonrpc="2.0"; id=1; method="tools/call"; params=@{ name=$Name; arguments=$Arguments } } | ConvertTo-Json -Depth 10 -Compress)
|
|
13
|
+
try {
|
|
14
|
+
$r = Invoke-WebRequest -Uri $base -Method POST -Headers $hdrs -ContentType "application/json" -Body $body -UseBasicParsing -TimeoutSec 15
|
|
15
|
+
if ($r.Content -match '(?s)data:\s*(\{.*\})') { return ($matches[1] | ConvertFrom-Json) }
|
|
16
|
+
return ($r.Content | ConvertFrom-Json)
|
|
17
|
+
} catch { return @{ error = @{ message = $_.Exception.Message } } }
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function Tool-Text {
|
|
21
|
+
param($r)
|
|
22
|
+
if ($r.error) { return "ERROR: $($r.error.message)" }
|
|
23
|
+
if ($r.result.content) { return ($r.result.content | ForEach-Object { $_.text }) -join "`n" }
|
|
24
|
+
return ($r | ConvertTo-Json -Depth 5 -Compress)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Write-Host ""
|
|
28
|
+
Write-Host "============================================"
|
|
29
|
+
Write-Host " UWP (Calculator + ApplicationFrameHost)"
|
|
30
|
+
Write-Host " Raw coordinate click test - no invoke_element shortcut"
|
|
31
|
+
Write-Host "============================================"
|
|
32
|
+
|
|
33
|
+
$null = Call-Tool "open_app" @{ name = "Calculator" }
|
|
34
|
+
Start-Sleep -Seconds 2
|
|
35
|
+
$null = Call-Tool "focus_window" @{ title = "Calculator" }
|
|
36
|
+
Start-Sleep -Milliseconds 500
|
|
37
|
+
|
|
38
|
+
# Clear the display first via invoke (known good)
|
|
39
|
+
$null = Call-Tool "invoke_element" @{ name = "Clear" }
|
|
40
|
+
Start-Sleep -Milliseconds 250
|
|
41
|
+
|
|
42
|
+
$tree = Tool-Text (Call-Tool "read_screen")
|
|
43
|
+
|
|
44
|
+
# Parse coords for Two, Plus, Three, Equals
|
|
45
|
+
$want = @("Two","Plus","Three","Equals")
|
|
46
|
+
$coords = @{}
|
|
47
|
+
foreach ($n in $want) {
|
|
48
|
+
# Lines look like: [Button] "Two" id:num2Button @171,489 77x51
|
|
49
|
+
$line = ($tree -split "`n") | Where-Object { $_ -match "\[Button\]\s+`"$n`"" } | Select-Object -First 1
|
|
50
|
+
if ($line -match "@(\d+),(\d+)\s+(\d+)x(\d+)") {
|
|
51
|
+
$bx = [int]$matches[1]; $by = [int]$matches[2]
|
|
52
|
+
$bw = [int]$matches[3]; $bh = [int]$matches[4]
|
|
53
|
+
$coords[$n] = @{ x = $bx + [int]($bw/2); y = $by + [int]($bh/2); raw = "$bx,$by ${bw}x$bh" }
|
|
54
|
+
Write-Host "[parse] $n bounds: $($coords[$n].raw) -> center ($($coords[$n].x),$($coords[$n].y))"
|
|
55
|
+
} else {
|
|
56
|
+
Write-Host "[parse] $n NOT FOUND in tree" -ForegroundColor Red
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
Write-Host ""
|
|
61
|
+
Write-Host "[click] Driving 2 + 3 = via mouse_click only (no invoke_element):"
|
|
62
|
+
foreach ($n in $want) {
|
|
63
|
+
if ($coords.ContainsKey($n)) {
|
|
64
|
+
$r = Call-Tool "mouse_click" @{ x = $coords[$n].x; y = $coords[$n].y }
|
|
65
|
+
Write-Host " mouse_click $n @ ($($coords[$n].x),$($coords[$n].y)) -> $(Tool-Text $r)"
|
|
66
|
+
Start-Sleep -Milliseconds 200
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
Start-Sleep -Milliseconds 400
|
|
71
|
+
$treeAfter = Tool-Text (Call-Tool "read_screen")
|
|
72
|
+
if ($treeAfter -match "Display is (\d+)") {
|
|
73
|
+
Write-Host ""
|
|
74
|
+
Write-Host ">>> Display shows: $($matches[1])"
|
|
75
|
+
if ($matches[1] -eq "5") {
|
|
76
|
+
Write-Host " PASS UWP raw-coord click chain produced correct result" -ForegroundColor Green
|
|
77
|
+
} else {
|
|
78
|
+
Write-Host " FAIL UWP raw-coord click chain produced WRONG result" -ForegroundColor Red
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# edge-glow.ps1 — "task in progress" screen-edge glow.
|
|
2
|
+
#
|
|
3
|
+
# A full-screen, CLICK-THROUGH, never-activating overlay that draws a soft glow
|
|
4
|
+
# on all four screen edges and pulses it dim<->bright while clawdcursor is
|
|
5
|
+
# driving the desktop. Spawned/killed by src/core/banner.ts in lockstep with the
|
|
6
|
+
# control-banner pill (pin() on task start, unpin()/idle to hide) — it runs
|
|
7
|
+
# ALONGSIDE the pill, which keeps the double-click-to-stop affordance.
|
|
8
|
+
#
|
|
9
|
+
# Why a per-pixel-alpha layered window (UpdateLayeredWindow) and not a plain
|
|
10
|
+
# WinForms paint + TransparencyKey: a color key can only knock out ONE exact
|
|
11
|
+
# color, so a soft inward fade can't be made click-through cleanly. Per-pixel
|
|
12
|
+
# alpha gives a real soft glow AND a fully click-through interior in one shot.
|
|
13
|
+
#
|
|
14
|
+
# Extended window styles (mirrors banner.ps1's zero-focus contract, plus
|
|
15
|
+
# click-through — critical: it is up WHILE the agent types/clicks):
|
|
16
|
+
# WS_EX_LAYERED 0x00080000 per-pixel alpha compositing
|
|
17
|
+
# WS_EX_TRANSPARENT 0x00000020 click-through (input falls to the app below)
|
|
18
|
+
# WS_EX_NOACTIVATE 0x08000000 never steals focus (agent keeps typing)
|
|
19
|
+
# WS_EX_TOOLWINDOW 0x00000080 no taskbar / alt-tab entry
|
|
20
|
+
# WS_EX_TOPMOST 0x00000008 stays above normal windows
|
|
21
|
+
#
|
|
22
|
+
# Defaults are production: amber, persistent (runs until the parent kills it).
|
|
23
|
+
# For a manual DEMO, pass -DurationSec so it self-closes, e.g.:
|
|
24
|
+
# powershell -NoProfile -ExecutionPolicy Bypass -File edge-glow.ps1 -DurationSec 12
|
|
25
|
+
#
|
|
26
|
+
# Windows-only today, same as the banner. macOS/Linux overlays are a follow-up.
|
|
27
|
+
|
|
28
|
+
param(
|
|
29
|
+
[string]$Color = '#f59e0b', # glow color (amber — "in progress")
|
|
30
|
+
[int] $Thickness = 80, # px depth the glow fades in from each edge
|
|
31
|
+
[int] $PeriodMs = 1600, # full dim->bright->dim cycle
|
|
32
|
+
[int] $MinAlpha = 60, # dim floor (0-255); lower = dims more
|
|
33
|
+
[int] $PeakAlpha = 200, # per-pixel alpha at the very edge (0-255)
|
|
34
|
+
[int] $DurationSec = 0 # 0 = run until killed; >0 = self-close (demo)
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
$ErrorActionPreference = 'Stop'
|
|
38
|
+
Add-Type -AssemblyName System.Windows.Forms
|
|
39
|
+
Add-Type -AssemblyName System.Drawing
|
|
40
|
+
|
|
41
|
+
Add-Type -ReferencedAssemblies System.Windows.Forms, System.Drawing -TypeDefinition @'
|
|
42
|
+
using System;
|
|
43
|
+
using System.Drawing;
|
|
44
|
+
using System.Runtime.InteropServices;
|
|
45
|
+
using System.Windows.Forms;
|
|
46
|
+
|
|
47
|
+
public class GlowOverlay : Form {
|
|
48
|
+
protected override bool ShowWithoutActivation { get { return true; } }
|
|
49
|
+
protected override CreateParams CreateParams {
|
|
50
|
+
get {
|
|
51
|
+
CreateParams cp = base.CreateParams;
|
|
52
|
+
cp.ExStyle |= 0x00080000; // WS_EX_LAYERED
|
|
53
|
+
cp.ExStyle |= 0x00000020; // WS_EX_TRANSPARENT (click-through)
|
|
54
|
+
cp.ExStyle |= 0x08000000; // WS_EX_NOACTIVATE
|
|
55
|
+
cp.ExStyle |= 0x00000080; // WS_EX_TOOLWINDOW
|
|
56
|
+
cp.ExStyle |= 0x00000008; // WS_EX_TOPMOST
|
|
57
|
+
return cp;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
[DllImport("user32.dll")] static extern IntPtr GetDC(IntPtr hWnd);
|
|
62
|
+
[DllImport("user32.dll")] static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
|
|
63
|
+
[DllImport("gdi32.dll")] static extern IntPtr CreateCompatibleDC(IntPtr hDC);
|
|
64
|
+
[DllImport("gdi32.dll")] static extern bool DeleteDC(IntPtr hdc);
|
|
65
|
+
[DllImport("gdi32.dll")] static extern IntPtr SelectObject(IntPtr hdc, IntPtr h);
|
|
66
|
+
[DllImport("gdi32.dll")] static extern bool DeleteObject(IntPtr ho);
|
|
67
|
+
[DllImport("user32.dll")] static extern bool UpdateLayeredWindow(
|
|
68
|
+
IntPtr hwnd, IntPtr hdcDst, ref POINT pptDst, ref SIZE psize,
|
|
69
|
+
IntPtr hdcSrc, ref POINT pptSrc, int crKey, ref BLENDFUNCTION pblend, int dwFlags);
|
|
70
|
+
|
|
71
|
+
[StructLayout(LayoutKind.Sequential)] public struct POINT { public int X, Y; public POINT(int x,int y){X=x;Y=y;} }
|
|
72
|
+
[StructLayout(LayoutKind.Sequential)] public struct SIZE { public int cx, cy; public SIZE(int x,int y){cx=x;cy=y;} }
|
|
73
|
+
[StructLayout(LayoutKind.Sequential, Pack=1)] public struct BLENDFUNCTION {
|
|
74
|
+
public byte BlendOp, BlendFlags, SourceConstantAlpha, AlphaFormat;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
IntPtr screenDc, memDc, hBitmap, oldBitmap;
|
|
78
|
+
Bitmap bmp;
|
|
79
|
+
|
|
80
|
+
public void SetBitmap(Bitmap b) {
|
|
81
|
+
bmp = b;
|
|
82
|
+
screenDc = GetDC(IntPtr.Zero);
|
|
83
|
+
memDc = CreateCompatibleDC(screenDc);
|
|
84
|
+
hBitmap = b.GetHbitmap(Color.FromArgb(0)); // ARGB DIB for ULW
|
|
85
|
+
oldBitmap = SelectObject(memDc, hBitmap);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Re-push the same bitmap with a new global alpha → smooth pulse.
|
|
89
|
+
public void Push(byte alpha) {
|
|
90
|
+
if (bmp == null) return;
|
|
91
|
+
SIZE size = new SIZE(bmp.Width, bmp.Height);
|
|
92
|
+
POINT src = new POINT(0, 0);
|
|
93
|
+
POINT dst = new POINT(this.Left, this.Top);
|
|
94
|
+
BLENDFUNCTION blend = new BLENDFUNCTION();
|
|
95
|
+
blend.BlendOp = 0; // AC_SRC_OVER
|
|
96
|
+
blend.BlendFlags = 0;
|
|
97
|
+
blend.SourceConstantAlpha = alpha;
|
|
98
|
+
blend.AlphaFormat = 1; // AC_SRC_ALPHA
|
|
99
|
+
UpdateLayeredWindow(this.Handle, screenDc, ref dst, ref size, memDc, ref src, 0, ref blend, 2); // ULW_ALPHA
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
public void Cleanup() {
|
|
103
|
+
if (memDc != IntPtr.Zero) SelectObject(memDc, oldBitmap);
|
|
104
|
+
if (hBitmap != IntPtr.Zero) { DeleteObject(hBitmap); hBitmap = IntPtr.Zero; }
|
|
105
|
+
if (memDc != IntPtr.Zero) { DeleteDC(memDc); memDc = IntPtr.Zero; }
|
|
106
|
+
if (screenDc != IntPtr.Zero) { ReleaseDC(IntPtr.Zero, screenDc); screenDc = IntPtr.Zero; }
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
'@
|
|
110
|
+
|
|
111
|
+
# ── Parse color ──
|
|
112
|
+
$hex = $Color.TrimStart('#')
|
|
113
|
+
$cr = [Convert]::ToInt32($hex.Substring(0,2),16)
|
|
114
|
+
$cg = [Convert]::ToInt32($hex.Substring(2,2),16)
|
|
115
|
+
$cb = [Convert]::ToInt32($hex.Substring(4,2),16)
|
|
116
|
+
|
|
117
|
+
# ── Cover the primary screen ──
|
|
118
|
+
$scr = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds
|
|
119
|
+
$W = $scr.Width
|
|
120
|
+
$H = $scr.Height
|
|
121
|
+
$T = [Math]::Min($Thickness, [Math]::Min([int]($W/2), [int]($H/2)))
|
|
122
|
+
|
|
123
|
+
# ── Render the edge glow into an ARGB bitmap once ──
|
|
124
|
+
$bmp = New-Object System.Drawing.Bitmap($W, $H, [System.Drawing.Imaging.PixelFormat]::Format32bppArgb)
|
|
125
|
+
$g = [System.Drawing.Graphics]::FromImage($bmp)
|
|
126
|
+
$g.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::AntiAlias
|
|
127
|
+
$g.Clear([System.Drawing.Color]::FromArgb(0,0,0,0))
|
|
128
|
+
|
|
129
|
+
$edge = [System.Drawing.Color]::FromArgb($PeakAlpha, $cr, $cg, $cb)
|
|
130
|
+
$fade = [System.Drawing.Color]::FromArgb(0, $cr, $cg, $cb)
|
|
131
|
+
$P = [System.Drawing.Point]
|
|
132
|
+
function New-Band($p1, $p2, $colorAt1, $colorAt2, $rect) {
|
|
133
|
+
$br = New-Object System.Drawing.Drawing2D.LinearGradientBrush($p1, $p2, $colorAt1, $colorAt2)
|
|
134
|
+
$br.WrapMode = [System.Drawing.Drawing2D.WrapMode]::TileFlipXY
|
|
135
|
+
$g.FillRectangle($br, $rect)
|
|
136
|
+
$br.Dispose()
|
|
137
|
+
}
|
|
138
|
+
# Corners deliberately overlap (additive glow pooling).
|
|
139
|
+
New-Band (New-Object $P 0,0) (New-Object $P 0,$T) $edge $fade (New-Object Drawing.Rectangle 0,0,$W,$T) # top
|
|
140
|
+
New-Band (New-Object $P 0,($H-$T)) (New-Object $P 0,$H) $fade $edge (New-Object Drawing.Rectangle 0,($H-$T),$W,$T) # bottom
|
|
141
|
+
New-Band (New-Object $P 0,0) (New-Object $P $T,0) $edge $fade (New-Object Drawing.Rectangle 0,0,$T,$H) # left
|
|
142
|
+
New-Band (New-Object $P ($W-$T),0) (New-Object $P $W,0) $fade $edge (New-Object Drawing.Rectangle ($W-$T),0,$T,$H) # right
|
|
143
|
+
$g.Dispose()
|
|
144
|
+
|
|
145
|
+
# ── Build the overlay window ──
|
|
146
|
+
$form = New-Object GlowOverlay
|
|
147
|
+
$form.FormBorderStyle = 'None'
|
|
148
|
+
$form.ShowInTaskbar = $false
|
|
149
|
+
$form.TopMost = $true
|
|
150
|
+
$form.StartPosition = 'Manual'
|
|
151
|
+
$form.Bounds = $scr
|
|
152
|
+
|
|
153
|
+
$startTicks = [Environment]::TickCount
|
|
154
|
+
|
|
155
|
+
$form.Add_Shown({
|
|
156
|
+
$form.SetBitmap($bmp)
|
|
157
|
+
$form.Push([byte]$MinAlpha)
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
# Pulse: cosine ease between MinAlpha and 255 (smooth dim<->bright).
|
|
161
|
+
$pulse = New-Object System.Windows.Forms.Timer
|
|
162
|
+
$pulse.Interval = 30
|
|
163
|
+
$pulse.Add_Tick({
|
|
164
|
+
$elapsed = [Environment]::TickCount - $startTicks
|
|
165
|
+
if ($DurationSec -gt 0 -and $elapsed -ge ($DurationSec * 1000)) {
|
|
166
|
+
$pulse.Stop()
|
|
167
|
+
$form.Cleanup()
|
|
168
|
+
$form.Close()
|
|
169
|
+
return
|
|
170
|
+
}
|
|
171
|
+
$phase = ($elapsed % $PeriodMs) / [double]$PeriodMs
|
|
172
|
+
$wave = (1 - [Math]::Cos($phase * 2 * [Math]::PI)) / 2 # 0->1->0
|
|
173
|
+
$alpha = [int]($MinAlpha + ($wave * (255 - $MinAlpha)))
|
|
174
|
+
if ($alpha -lt 0) { $alpha = 0 } elseif ($alpha -gt 255) { $alpha = 255 }
|
|
175
|
+
$form.Push([byte]$alpha)
|
|
176
|
+
})
|
|
177
|
+
$pulse.Start()
|
|
178
|
+
|
|
179
|
+
[System.Windows.Forms.Application]::Run($form)
|
|
180
|
+
$bmp.Dispose()
|