@anionex/dsh-computer-use 0.1.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 (120) hide show
  1. package/LICENSE +21 -0
  2. package/README.i18n.yaml +6 -0
  3. package/README.md +307 -0
  4. package/README.zh.md +307 -0
  5. package/assets/computer-use-fixture.png +0 -0
  6. package/assets/cursor.png +0 -0
  7. package/cordis.patch.yml +13 -0
  8. package/docs/interaction-policy.i18n.yaml +4 -0
  9. package/docs/interaction-policy.md +140 -0
  10. package/docs/interaction-policy.zh.md +140 -0
  11. package/lib/approval-policy.js +12 -0
  12. package/lib/approval-policy.js.map +1 -0
  13. package/lib/artifacts.js +79 -0
  14. package/lib/artifacts.js.map +1 -0
  15. package/lib/backend.js +3 -0
  16. package/lib/backend.js.map +1 -0
  17. package/lib/client.js +349 -0
  18. package/lib/client.js.map +1 -0
  19. package/lib/config.js +120 -0
  20. package/lib/config.js.map +1 -0
  21. package/lib/confirmations.js +99 -0
  22. package/lib/confirmations.js.map +1 -0
  23. package/lib/diff.js +58 -0
  24. package/lib/diff.js.map +1 -0
  25. package/lib/errors.js +22 -0
  26. package/lib/errors.js.map +1 -0
  27. package/lib/exposure.js +231 -0
  28. package/lib/exposure.js.map +1 -0
  29. package/lib/index.js +56 -0
  30. package/lib/index.js.map +1 -0
  31. package/lib/leases.js +259 -0
  32. package/lib/leases.js.map +1 -0
  33. package/lib/providers/macos.js +148 -0
  34. package/lib/providers/macos.js.map +1 -0
  35. package/lib/providers/native-helper.js +356 -0
  36. package/lib/providers/native-helper.js.map +1 -0
  37. package/lib/service.js +480 -0
  38. package/lib/service.js.map +1 -0
  39. package/lib/skill.js +119 -0
  40. package/lib/skill.js.map +1 -0
  41. package/lib/target-resolver.js +180 -0
  42. package/lib/target-resolver.js.map +1 -0
  43. package/lib/tools.js +493 -0
  44. package/lib/tools.js.map +1 -0
  45. package/lib/types/approval-policy.d.ts +13 -0
  46. package/lib/types/approval-policy.d.ts.map +1 -0
  47. package/lib/types/artifacts.d.ts +10 -0
  48. package/lib/types/artifacts.d.ts.map +1 -0
  49. package/lib/types/backend.d.ts +94 -0
  50. package/lib/types/backend.d.ts.map +1 -0
  51. package/lib/types/client/index.d.ts +78 -0
  52. package/lib/types/client/index.d.ts.map +1 -0
  53. package/lib/types/config.d.ts +75 -0
  54. package/lib/types/config.d.ts.map +1 -0
  55. package/lib/types/confirmations.d.ts +23 -0
  56. package/lib/types/confirmations.d.ts.map +1 -0
  57. package/lib/types/diff.d.ts +5 -0
  58. package/lib/types/diff.d.ts.map +1 -0
  59. package/lib/types/errors.d.ts +15 -0
  60. package/lib/types/errors.d.ts.map +1 -0
  61. package/lib/types/exposure.d.ts +30 -0
  62. package/lib/types/exposure.d.ts.map +1 -0
  63. package/lib/types/index.d.ts +21 -0
  64. package/lib/types/index.d.ts.map +1 -0
  65. package/lib/types/leases.d.ts +80 -0
  66. package/lib/types/leases.d.ts.map +1 -0
  67. package/lib/types/providers/macos.d.ts +15 -0
  68. package/lib/types/providers/macos.d.ts.map +1 -0
  69. package/lib/types/providers/native-helper.d.ts +36 -0
  70. package/lib/types/providers/native-helper.d.ts.map +1 -0
  71. package/lib/types/service.d.ts +52 -0
  72. package/lib/types/service.d.ts.map +1 -0
  73. package/lib/types/skill.d.ts +9 -0
  74. package/lib/types/skill.d.ts.map +1 -0
  75. package/lib/types/target-resolver.d.ts +38 -0
  76. package/lib/types/target-resolver.d.ts.map +1 -0
  77. package/lib/types/tools.d.ts +6 -0
  78. package/lib/types/tools.d.ts.map +1 -0
  79. package/lib/types/types.d.ts +246 -0
  80. package/lib/types/types.d.ts.map +1 -0
  81. package/lib/types/web.d.ts +32 -0
  82. package/lib/types/web.d.ts.map +1 -0
  83. package/lib/types.js +9 -0
  84. package/lib/types.js.map +1 -0
  85. package/lib/web.js +163 -0
  86. package/lib/web.js.map +1 -0
  87. package/native/macos/Sources/Fixture/main.swift +366 -0
  88. package/native/macos/Sources/Helper/CursorImage.swift +11 -0
  89. package/native/macos/Sources/Helper/CursorOverlay.swift +488 -0
  90. package/native/macos/Sources/Helper/TargetedPointer.swift +314 -0
  91. package/native/macos/Sources/Helper/main.swift +1140 -0
  92. package/native/macos/Sources/Monitor/main.swift +139 -0
  93. package/native/macos/bin/dsh-computer-use-helper +0 -0
  94. package/native/macos/manifest.json +14 -0
  95. package/package.json +128 -0
  96. package/scripts/build-client.mjs +24 -0
  97. package/scripts/build-native.mjs +158 -0
  98. package/scripts/check-native.mjs +92 -0
  99. package/scripts/model-e2e.mjs +291 -0
  100. package/scripts/session-transcript.mjs +117 -0
  101. package/scripts/validate.mjs +256 -0
  102. package/src/approval-policy.ts +16 -0
  103. package/src/artifacts.ts +93 -0
  104. package/src/backend.ts +103 -0
  105. package/src/client/index.tsx +539 -0
  106. package/src/config.ts +196 -0
  107. package/src/confirmations.ts +128 -0
  108. package/src/diff.ts +52 -0
  109. package/src/errors.ts +39 -0
  110. package/src/exposure.ts +236 -0
  111. package/src/index.ts +66 -0
  112. package/src/leases.ts +337 -0
  113. package/src/providers/macos.ts +185 -0
  114. package/src/providers/native-helper.ts +393 -0
  115. package/src/service.ts +583 -0
  116. package/src/skill.ts +123 -0
  117. package/src/target-resolver.ts +237 -0
  118. package/src/tools.ts +528 -0
  119. package/src/types.ts +299 -0
  120. package/src/web.ts +180 -0
@@ -0,0 +1,314 @@
1
+ import CoreGraphics
2
+ import Darwin
3
+ import Foundation
4
+
5
+ struct TargetedPointerError: Error {
6
+ let message: String
7
+ }
8
+
9
+ struct TargetedPointerTarget {
10
+ let pid: pid_t
11
+ let windowNumber: Int64
12
+ let windowFrame: CGRect
13
+
14
+ func localPoint(for screenPoint: CGPoint) -> CGPoint {
15
+ CGPoint(
16
+ x: screenPoint.x - windowFrame.origin.x,
17
+ y: screenPoint.y - windowFrame.origin.y
18
+ )
19
+ }
20
+ }
21
+
22
+ private typealias PostToPidFunction = @convention(c) (pid_t, UnsafeMutableRawPointer?) -> Void
23
+ private typealias SetIntegerFieldFunction = @convention(c) (UnsafeMutableRawPointer?, UInt32, Int64) -> Void
24
+ private typealias SetWindowLocationFunction = @convention(c) (UnsafeMutableRawPointer?, Double, Double) -> Void
25
+
26
+ private final class SkyLightPointerBridge {
27
+ static let shared = SkyLightPointerBridge()
28
+
29
+ private let handle: UnsafeMutableRawPointer?
30
+ private let postToPid: PostToPidFunction?
31
+ private let setIntegerField: SetIntegerFieldFunction?
32
+ private let setWindowLocation: SetWindowLocationFunction?
33
+
34
+ private init() {
35
+ handle = dlopen(
36
+ "/System/Library/PrivateFrameworks/SkyLight.framework/SkyLight",
37
+ RTLD_LAZY | RTLD_GLOBAL
38
+ )
39
+ postToPid = Self.resolve(handle, "SLEventPostToPid", as: PostToPidFunction.self)
40
+ setIntegerField = Self.resolve(handle, "SLEventSetIntegerValueField", as: SetIntegerFieldFunction.self)
41
+ setWindowLocation = Self.resolve(handle, "CGEventSetWindowLocation", as: SetWindowLocationFunction.self)
42
+ }
43
+
44
+ deinit {
45
+ if let handle { dlclose(handle) }
46
+ }
47
+
48
+ private static func resolve<T>(_ handle: UnsafeMutableRawPointer?, _ name: String, as type: T.Type) -> T? {
49
+ guard let handle, let symbol = dlsym(handle, name) else { return nil }
50
+ return unsafeBitCast(symbol, to: type)
51
+ }
52
+
53
+ var isAvailable: Bool {
54
+ postToPid != nil && setIntegerField != nil && setWindowLocation != nil
55
+ }
56
+
57
+ func post(
58
+ _ event: CGEvent,
59
+ target: TargetedPointerTarget,
60
+ localPoint: CGPoint,
61
+ clickState: Int64,
62
+ buttonNumber: Int64,
63
+ subtype: Int64,
64
+ gesturePhase: Int64,
65
+ clickGroup: Int64
66
+ ) throws {
67
+ guard let postToPid, let setIntegerField, let setWindowLocation else {
68
+ throw TargetedPointerError(message: "SkyLight target-process pointer routing is unavailable")
69
+ }
70
+ let pointer = Unmanaged.passUnretained(event).toOpaque()
71
+ setWindowLocation(pointer, localPoint.x, localPoint.y)
72
+ setIntegerField(pointer, 0, gesturePhase)
73
+ setIntegerField(pointer, 1, clickState)
74
+ setIntegerField(pointer, 3, buttonNumber)
75
+ setIntegerField(pointer, 7, subtype)
76
+ setIntegerField(pointer, 40, Int64(target.pid))
77
+ setIntegerField(pointer, 51, target.windowNumber)
78
+ setIntegerField(pointer, 58, clickGroup)
79
+ setIntegerField(pointer, 91, target.windowNumber)
80
+ setIntegerField(pointer, 92, target.windowNumber)
81
+
82
+ postToPid(target.pid, pointer)
83
+ }
84
+ }
85
+
86
+ private func targetedPointerSource() throws -> CGEventSource {
87
+ guard SkyLightPointerBridge.shared.isAvailable else {
88
+ throw TargetedPointerError(message: "SkyLight target-process pointer routing is unavailable")
89
+ }
90
+ guard let source = CGEventSource(stateID: .privateState) else {
91
+ throw TargetedPointerError(message: "CoreGraphics pointer event source is unavailable")
92
+ }
93
+ return source
94
+ }
95
+
96
+ private func clickGroup() -> Int64 {
97
+ Int64(DispatchTime.now().uptimeNanoseconds & 0x7fff_ffff)
98
+ }
99
+
100
+ private func buttonNumber(_ button: CGMouseButton) -> Int64 {
101
+ switch button {
102
+ case .right: return 1
103
+ case .center: return 2
104
+ default: return 0
105
+ }
106
+ }
107
+
108
+ private func pointerEvent(
109
+ source: CGEventSource,
110
+ type: CGEventType,
111
+ button: CGMouseButton
112
+ ) throws -> CGEvent {
113
+ let cursorLocation = CGEvent(source: nil)?.location ?? .zero
114
+ guard let event = CGEvent(
115
+ mouseEventSource: source,
116
+ mouseType: type,
117
+ mouseCursorPosition: cursorLocation,
118
+ mouseButton: button
119
+ ) else {
120
+ throw TargetedPointerError(message: "CoreGraphics could not create a pointer event")
121
+ }
122
+ return event
123
+ }
124
+
125
+ private func postPointerEvent(
126
+ _ event: CGEvent,
127
+ target: TargetedPointerTarget,
128
+ point: CGPoint,
129
+ clickState: Int64,
130
+ buttonNumber: Int64,
131
+ subtype: Int64,
132
+ gesturePhase: Int64,
133
+ clickGroup: Int64
134
+ ) throws {
135
+ try SkyLightPointerBridge.shared.post(
136
+ event,
137
+ target: target,
138
+ localPoint: target.localPoint(for: point),
139
+ clickState: clickState,
140
+ buttonNumber: buttonNumber,
141
+ subtype: subtype,
142
+ gesturePhase: gesturePhase,
143
+ clickGroup: clickGroup
144
+ )
145
+ }
146
+
147
+ func targetedClick(
148
+ at point: CGPoint,
149
+ button: CGMouseButton,
150
+ count: Int,
151
+ target: TargetedPointerTarget
152
+ ) throws {
153
+ let source = try targetedPointerSource()
154
+ let group = clickGroup()
155
+ let number = buttonNumber(button)
156
+ let moved = try pointerEvent(source: source, type: .mouseMoved, button: .left)
157
+ try postPointerEvent(
158
+ moved,
159
+ target: target,
160
+ point: point,
161
+ clickState: 0,
162
+ buttonNumber: 0,
163
+ subtype: 3,
164
+ gesturePhase: 2,
165
+ clickGroup: group
166
+ )
167
+ usleep(12_000)
168
+
169
+ let downType: CGEventType = button == .right ? .rightMouseDown : button == .center ? .otherMouseDown : .leftMouseDown
170
+ let upType: CGEventType = button == .right ? .rightMouseUp : button == .center ? .otherMouseUp : .leftMouseUp
171
+ for pair in 1...max(1, count) {
172
+ let down = try pointerEvent(source: source, type: downType, button: button)
173
+ down.setDoubleValueField(.mouseEventPressure, value: 1)
174
+ try postPointerEvent(
175
+ down,
176
+ target: target,
177
+ point: point,
178
+ clickState: Int64(pair),
179
+ buttonNumber: number,
180
+ subtype: 3,
181
+ gesturePhase: 3,
182
+ clickGroup: group
183
+ )
184
+ usleep(28_000)
185
+
186
+ let up = try pointerEvent(source: source, type: upType, button: button)
187
+ up.setDoubleValueField(.mouseEventPressure, value: 0)
188
+ try postPointerEvent(
189
+ up,
190
+ target: target,
191
+ point: point,
192
+ clickState: Int64(pair),
193
+ buttonNumber: number,
194
+ subtype: 3,
195
+ gesturePhase: 3,
196
+ clickGroup: group
197
+ )
198
+ if pair < count { usleep(80_000) }
199
+ }
200
+ }
201
+
202
+ func targetedScroll(
203
+ at point: CGPoint,
204
+ vertical: Int32,
205
+ horizontal: Int32,
206
+ target: TargetedPointerTarget
207
+ ) throws {
208
+ let source = try targetedPointerSource()
209
+ let group = clickGroup()
210
+ let moved = try pointerEvent(source: source, type: .mouseMoved, button: .left)
211
+ try postPointerEvent(
212
+ moved,
213
+ target: target,
214
+ point: point,
215
+ clickState: 0,
216
+ buttonNumber: 0,
217
+ subtype: 0,
218
+ gesturePhase: 2,
219
+ clickGroup: group
220
+ )
221
+ usleep(12_000)
222
+
223
+ guard let event = CGEvent(
224
+ scrollWheelEvent2Source: source,
225
+ units: .line,
226
+ wheelCount: 2,
227
+ wheel1: vertical,
228
+ wheel2: horizontal,
229
+ wheel3: 0
230
+ ) else {
231
+ throw TargetedPointerError(message: "CoreGraphics could not create a scroll event")
232
+ }
233
+ event.location = CGEvent(source: nil)?.location ?? .zero
234
+ try postPointerEvent(
235
+ event,
236
+ target: target,
237
+ point: point,
238
+ clickState: 0,
239
+ buttonNumber: 0,
240
+ subtype: 0,
241
+ gesturePhase: 2,
242
+ clickGroup: group
243
+ )
244
+ }
245
+
246
+ func targetedDrag(
247
+ from: CGPoint,
248
+ to: CGPoint,
249
+ target: TargetedPointerTarget
250
+ ) throws {
251
+ let source = try targetedPointerSource()
252
+ let group = clickGroup()
253
+ let moved = try pointerEvent(source: source, type: .mouseMoved, button: .left)
254
+ try postPointerEvent(
255
+ moved,
256
+ target: target,
257
+ point: from,
258
+ clickState: 0,
259
+ buttonNumber: 0,
260
+ subtype: 0,
261
+ gesturePhase: 2,
262
+ clickGroup: group
263
+ )
264
+ usleep(12_000)
265
+
266
+ let down = try pointerEvent(source: source, type: .leftMouseDown, button: .left)
267
+ down.setDoubleValueField(.mouseEventPressure, value: 1)
268
+ try postPointerEvent(
269
+ down,
270
+ target: target,
271
+ point: from,
272
+ clickState: 1,
273
+ buttonNumber: 0,
274
+ subtype: 0,
275
+ gesturePhase: 3,
276
+ clickGroup: group
277
+ )
278
+ usleep(16_000)
279
+
280
+ for step in 1...12 {
281
+ let fraction = CGFloat(step) / 12
282
+ let point = CGPoint(
283
+ x: from.x + (to.x - from.x) * fraction,
284
+ y: from.y + (to.y - from.y) * fraction
285
+ )
286
+ let dragged = try pointerEvent(source: source, type: .leftMouseDragged, button: .left)
287
+ dragged.setDoubleValueField(.mouseEventPressure, value: 1)
288
+ try postPointerEvent(
289
+ dragged,
290
+ target: target,
291
+ point: point,
292
+ clickState: 1,
293
+ buttonNumber: 0,
294
+ subtype: 0,
295
+ gesturePhase: 3,
296
+ clickGroup: group
297
+ )
298
+ usleep(12_000)
299
+ }
300
+ usleep(50_000)
301
+
302
+ let up = try pointerEvent(source: source, type: .leftMouseUp, button: .left)
303
+ up.setDoubleValueField(.mouseEventPressure, value: 0)
304
+ try postPointerEvent(
305
+ up,
306
+ target: target,
307
+ point: to,
308
+ clickState: 1,
309
+ buttonNumber: 0,
310
+ subtype: 0,
311
+ gesturePhase: 3,
312
+ clickGroup: group
313
+ )
314
+ }