@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,366 @@
1
+ import AppKit
2
+ import Foundation
3
+
4
+ private final class InputProbeView: NSView {
5
+ var onEvent: ((String) -> Void)?
6
+ private var dragging = false
7
+
8
+ override var isFlipped: Bool { true }
9
+
10
+ override init(frame frameRect: NSRect) {
11
+ super.init(frame: frameRect)
12
+ wantsLayer = true
13
+ layer?.backgroundColor = NSColor.controlBackgroundColor.cgColor
14
+ layer?.borderColor = NSColor.separatorColor.cgColor
15
+ layer?.borderWidth = 1
16
+ layer?.cornerRadius = 8
17
+ setAccessibilityElement(true)
18
+ setAccessibilityRole(.group)
19
+ setAccessibilityLabel("Targeted pointer probe")
20
+ }
21
+
22
+ required init?(coder: NSCoder) {
23
+ fatalError("init(coder:) has not been implemented")
24
+ }
25
+
26
+ override func acceptsFirstMouse(for event: NSEvent?) -> Bool { true }
27
+
28
+ override func mouseDown(with event: NSEvent) {
29
+ dragging = true
30
+ onEvent?("pointer down")
31
+ }
32
+
33
+ override func mouseDragged(with event: NSEvent) {
34
+ guard dragging else { return }
35
+ onEvent?("pointer drag")
36
+ }
37
+
38
+ override func mouseUp(with event: NSEvent) {
39
+ let wasDragging = dragging
40
+ dragging = false
41
+ onEvent?(wasDragging ? "pointer up" : "pointer up without down")
42
+ }
43
+
44
+ override func scrollWheel(with event: NSEvent) {
45
+ onEvent?("pointer scroll")
46
+ }
47
+
48
+ override func draw(_ dirtyRect: NSRect) {
49
+ super.draw(dirtyRect)
50
+ let text = "Targeted pointer probe"
51
+ let attributes: [NSAttributedString.Key: Any] = [
52
+ .font: NSFont.systemFont(ofSize: 13, weight: .medium),
53
+ .foregroundColor: NSColor.secondaryLabelColor,
54
+ ]
55
+ let size = text.size(withAttributes: attributes)
56
+ text.draw(at: NSPoint(x: (bounds.width - size.width) / 2, y: (bounds.height - size.height) / 2), withAttributes: attributes)
57
+ }
58
+ }
59
+
60
+ private final class FixtureDelegate: NSObject, NSApplicationDelegate {
61
+ private var window: NSWindow!
62
+ private var textField: NSTextField!
63
+ private var secureField: NSSecureTextField!
64
+ private var checkbox: NSButton!
65
+ private var popup: NSPopUpButton!
66
+ private var slider: NSSlider!
67
+ private var statusLabel: NSTextField!
68
+ private var inputProbe: InputProbeView!
69
+ private var stack: NSStackView!
70
+ private var insertedHarmlessSibling = false
71
+ private var keyMonitor: Any?
72
+ private var reorderTimer: Timer?
73
+ private var pointerClickCount = 0
74
+ private var pointerScrollCount = 0
75
+ private var pointerDragCount = 0
76
+ private var pointerMouseDownCount = 0
77
+ private var pointerMouseUpCount = 0
78
+ private var pointerDragGestureCount = 0
79
+ private var activeDragGesture = false
80
+ private var activationCount = 0
81
+ private let transcriptPath: String?
82
+ private let reorderTriggerPath: String?
83
+ private let launchInBackground: Bool
84
+
85
+ override init() {
86
+ let arguments = ProcessInfo.processInfo.arguments
87
+ if let index = arguments.firstIndex(of: "--transcript"), arguments.indices.contains(index + 1) {
88
+ transcriptPath = arguments[index + 1]
89
+ } else {
90
+ transcriptPath = nil
91
+ }
92
+ if let index = arguments.firstIndex(of: "--reorder-trigger"), arguments.indices.contains(index + 1) {
93
+ reorderTriggerPath = arguments[index + 1]
94
+ } else {
95
+ reorderTriggerPath = nil
96
+ }
97
+ launchInBackground = arguments.contains("--background")
98
+ super.init()
99
+ }
100
+
101
+ func applicationDidFinishLaunching(_ notification: Notification) {
102
+ buildWindow()
103
+ keyMonitor = NSEvent.addLocalMonitorForEvents(matching: .keyDown) { [weak self] event in
104
+ guard event.keyCode == 36 else { return event }
105
+ self?.applyValues()
106
+ return nil
107
+ }
108
+ if launchInBackground {
109
+ window.orderFrontRegardless()
110
+ window.orderBack(nil)
111
+ } else {
112
+ NSApplication.shared.activate(ignoringOtherApps: true)
113
+ window.makeKeyAndOrderFront(nil)
114
+ }
115
+ writeTranscript(event: "ready")
116
+ if let reorderTriggerPath {
117
+ reorderTimer = Timer.scheduledTimer(withTimeInterval: 0.05, repeats: true) { [weak self] timer in
118
+ guard FileManager.default.fileExists(atPath: reorderTriggerPath) else { return }
119
+ timer.invalidate()
120
+ self?.insertHarmlessSibling()
121
+ }
122
+ }
123
+ }
124
+
125
+ func applicationDidBecomeActive(_ notification: Notification) {
126
+ activationCount += 1
127
+ writeTranscript(event: "activated")
128
+ }
129
+
130
+ func applicationWillTerminate(_ notification: Notification) {
131
+ if let keyMonitor { NSEvent.removeMonitor(keyMonitor) }
132
+ reorderTimer?.invalidate()
133
+ }
134
+
135
+ func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
136
+ true
137
+ }
138
+
139
+ private func buildWindow() {
140
+ window = NSWindow(
141
+ contentRect: NSRect(x: 0, y: 0, width: 760, height: 560),
142
+ styleMask: [.titled, .closable, .miniaturizable, .resizable],
143
+ backing: .buffered,
144
+ defer: false
145
+ )
146
+ window.title = "DSH Computer Use Fixture"
147
+ window.center()
148
+ window.setFrameAutosaveName("dsh-computer-use-fixture")
149
+
150
+ let content = NSView()
151
+ content.translatesAutoresizingMaskIntoConstraints = false
152
+ window.contentView = content
153
+
154
+ let title = NSTextField(labelWithString: "Computer Use deterministic fixture")
155
+ title.font = .systemFont(ofSize: 22, weight: .semibold)
156
+ title.setAccessibilityLabel("Fixture title")
157
+
158
+ textField = NSTextField(string: "initial text")
159
+ textField.placeholderString = "Editable text"
160
+ textField.setAccessibilityLabel("Editable text")
161
+ textField.identifier = NSUserInterfaceItemIdentifier("fixture.text")
162
+ textField.target = self
163
+ textField.action = #selector(applyValues)
164
+
165
+ secureField = NSSecureTextField(string: "fixture-secret")
166
+ secureField.placeholderString = "Secure text"
167
+ secureField.setAccessibilityLabel("Secure text")
168
+ secureField.identifier = NSUserInterfaceItemIdentifier("fixture.secure")
169
+
170
+ checkbox = makeCheckbox(state: .off)
171
+
172
+ popup = NSPopUpButton(frame: .zero, pullsDown: false)
173
+ popup.addItems(withTitles: ["Alpha", "Beta", "Gamma"])
174
+ popup.selectItem(at: 0)
175
+ popup.target = self
176
+ popup.action = #selector(selectPopup)
177
+ popup.setAccessibilityLabel("Fixture selection")
178
+
179
+ slider = NSSlider(value: 25, minValue: 0, maxValue: 100, target: self, action: #selector(changeSlider))
180
+ slider.setAccessibilityLabel("Fixture slider")
181
+
182
+ let apply = NSButton(title: "Apply", target: self, action: #selector(applyValues))
183
+ apply.bezelStyle = .rounded
184
+ apply.keyEquivalent = "\r"
185
+ apply.setAccessibilityLabel("Apply fixture values")
186
+
187
+ let delayed = NSButton(title: "Delayed update", target: self, action: #selector(delayedUpdate))
188
+ delayed.bezelStyle = .rounded
189
+ delayed.setAccessibilityLabel("Start delayed update")
190
+
191
+ let modal = NSButton(title: "Show modal", target: self, action: #selector(showModal))
192
+ modal.bezelStyle = .rounded
193
+ modal.setAccessibilityLabel("Show fixture modal")
194
+
195
+ statusLabel = NSTextField(labelWithString: "Status: ready")
196
+ statusLabel.font = .monospacedSystemFont(ofSize: 13, weight: .regular)
197
+ statusLabel.setAccessibilityLabel("Fixture status")
198
+ statusLabel.identifier = NSUserInterfaceItemIdentifier("fixture.status")
199
+
200
+ inputProbe = InputProbeView(frame: .zero)
201
+ inputProbe.translatesAutoresizingMaskIntoConstraints = false
202
+ inputProbe.heightAnchor.constraint(equalToConstant: 54).isActive = true
203
+ inputProbe.onEvent = { [weak self] event in
204
+ guard let self else { return }
205
+ switch event {
206
+ case "pointer down":
207
+ self.pointerMouseDownCount += 1
208
+ self.activeDragGesture = false
209
+ return
210
+ case "pointer drag":
211
+ self.pointerDragCount += 1
212
+ self.activeDragGesture = true
213
+ self.statusLabel.stringValue = "Status: pointer drag"
214
+ case "pointer up":
215
+ self.pointerMouseUpCount += 1
216
+ if self.activeDragGesture {
217
+ self.pointerDragGestureCount += 1
218
+ self.statusLabel.stringValue = "Status: pointer drag"
219
+ } else {
220
+ self.pointerClickCount += 1
221
+ self.statusLabel.stringValue = "Status: pointer click"
222
+ }
223
+ self.activeDragGesture = false
224
+ case "pointer scroll":
225
+ self.pointerScrollCount += 1
226
+ self.statusLabel.stringValue = "Status: pointer scroll"
227
+ default: break
228
+ }
229
+ self.writeTranscript(event: event)
230
+ }
231
+
232
+ let longText = (1...80).map { "Scrollable row \($0)" }.joined(separator: "\n")
233
+ let textView = NSTextView()
234
+ textView.string = longText
235
+ textView.isEditable = false
236
+ textView.isSelectable = true
237
+ textView.setAccessibilityLabel("Scrollable fixture rows")
238
+ let scroll = NSScrollView()
239
+ scroll.hasVerticalScroller = true
240
+ scroll.documentView = textView
241
+ scroll.heightAnchor.constraint(equalToConstant: 180).isActive = true
242
+
243
+ let fields = NSGridView(views: [
244
+ [NSTextField(labelWithString: "Text"), textField],
245
+ [NSTextField(labelWithString: "Secret"), secureField],
246
+ [NSTextField(labelWithString: "Selection"), popup],
247
+ [NSTextField(labelWithString: "Level"), slider],
248
+ ])
249
+ fields.rowSpacing = 10
250
+ fields.columnSpacing = 14
251
+ fields.column(at: 0).xPlacement = .trailing
252
+ fields.column(at: 1).width = 460
253
+
254
+ let buttons = NSStackView(views: [apply, delayed, modal])
255
+ buttons.orientation = .horizontal
256
+ buttons.spacing = 10
257
+
258
+ stack = NSStackView(views: [title, fields, checkbox, buttons, statusLabel, inputProbe, scroll])
259
+ stack.translatesAutoresizingMaskIntoConstraints = false
260
+ stack.orientation = .vertical
261
+ stack.alignment = .leading
262
+ stack.spacing = 16
263
+ content.addSubview(stack)
264
+ NSLayoutConstraint.activate([
265
+ stack.leadingAnchor.constraint(equalTo: content.leadingAnchor, constant: 28),
266
+ stack.trailingAnchor.constraint(equalTo: content.trailingAnchor, constant: -28),
267
+ stack.topAnchor.constraint(equalTo: content.topAnchor, constant: 24),
268
+ stack.bottomAnchor.constraint(lessThanOrEqualTo: content.bottomAnchor, constant: -24),
269
+ scroll.widthAnchor.constraint(equalTo: stack.widthAnchor),
270
+ inputProbe.widthAnchor.constraint(equalTo: stack.widthAnchor),
271
+ ])
272
+ window.makeFirstResponder(textField)
273
+ }
274
+
275
+ @objc private func applyValues() {
276
+ statusLabel.stringValue = "Status: applied \(textField.stringValue)"
277
+ writeTranscript(event: "apply")
278
+ }
279
+
280
+ @objc private func toggleCheckbox() {
281
+ statusLabel.stringValue = checkbox.state == .on ? "Status: option enabled" : "Status: option disabled"
282
+ writeTranscript(event: "checkbox")
283
+ }
284
+
285
+ @objc private func selectPopup() {
286
+ statusLabel.stringValue = "Status: selected \(popup.titleOfSelectedItem ?? "")"
287
+ writeTranscript(event: "selection")
288
+ }
289
+
290
+ @objc private func changeSlider() {
291
+ statusLabel.stringValue = "Status: slider \(Int(slider.doubleValue))"
292
+ writeTranscript(event: "slider")
293
+ }
294
+
295
+ @objc private func delayedUpdate() {
296
+ statusLabel.stringValue = "Status: waiting"
297
+ writeTranscript(event: "delay-start")
298
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
299
+ self?.statusLabel.stringValue = "Status: delayed complete"
300
+ self?.writeTranscript(event: "delay-complete")
301
+ }
302
+ }
303
+
304
+ private func insertHarmlessSibling() {
305
+ guard !insertedHarmlessSibling else { return }
306
+ insertedHarmlessSibling = true
307
+ let checkboxState = checkbox.state
308
+ stack.removeArrangedSubview(checkbox)
309
+ checkbox.removeFromSuperview()
310
+ let label = NSTextField(labelWithString: "Harmless dynamic sibling")
311
+ label.setAccessibilityLabel("Harmless dynamic sibling")
312
+ label.identifier = NSUserInterfaceItemIdentifier("fixture.harmless-sibling")
313
+ stack.insertArrangedSubview(label, at: 2)
314
+ checkbox = makeCheckbox(state: checkboxState)
315
+ stack.insertArrangedSubview(checkbox, at: 3)
316
+ statusLabel.stringValue = "Status: harmless sibling inserted"
317
+ writeTranscript(event: "reorder")
318
+ }
319
+
320
+ private func makeCheckbox(state: NSControl.StateValue) -> NSButton {
321
+ let value = NSButton(checkboxWithTitle: "Enable deterministic option", target: self, action: #selector(toggleCheckbox))
322
+ value.state = state
323
+ value.setAccessibilityLabel("Enable deterministic option")
324
+ value.identifier = NSUserInterfaceItemIdentifier("fixture.checkbox")
325
+ return value
326
+ }
327
+
328
+ @objc private func showModal() {
329
+ let alert = NSAlert()
330
+ alert.messageText = "Fixture modal"
331
+ alert.informativeText = "This modal exists for deterministic Accessibility observation."
332
+ alert.addButton(withTitle: "Confirm")
333
+ alert.beginSheetModal(for: window) { [weak self] _ in
334
+ self?.statusLabel.stringValue = "Status: modal confirmed"
335
+ self?.writeTranscript(event: "modal")
336
+ }
337
+ }
338
+
339
+ private func writeTranscript(event: String) {
340
+ guard let transcriptPath else { return }
341
+ let payload: [String: Any] = [
342
+ "event": event,
343
+ "text": textField?.stringValue ?? "",
344
+ "secureLength": secureField?.stringValue.count ?? 0,
345
+ "checked": checkbox?.state == .on,
346
+ "selection": popup?.titleOfSelectedItem ?? "",
347
+ "slider": Int(slider?.doubleValue ?? 0),
348
+ "status": statusLabel?.stringValue ?? "",
349
+ "pointerClickCount": pointerClickCount,
350
+ "pointerScrollCount": pointerScrollCount,
351
+ "pointerDragCount": pointerDragCount,
352
+ "pointerMouseDownCount": pointerMouseDownCount,
353
+ "pointerMouseUpCount": pointerMouseUpCount,
354
+ "pointerDragGestureCount": pointerDragGestureCount,
355
+ "activationCount": activationCount,
356
+ ]
357
+ guard let data = try? JSONSerialization.data(withJSONObject: payload, options: [.sortedKeys]) else { return }
358
+ try? data.write(to: URL(fileURLWithPath: transcriptPath), options: .atomic)
359
+ }
360
+ }
361
+
362
+ let app = NSApplication.shared
363
+ private let delegate = FixtureDelegate()
364
+ app.delegate = delegate
365
+ app.setActivationPolicy(.regular)
366
+ app.run()
@@ -0,0 +1,11 @@
1
+ import AppKit
2
+
3
+ /// Source asset: assets/cursor.png (whole image, 64x64, hotspot at top-left).
4
+ /// The overlay draws it at 28x28 points with the top-left corner at the target.
5
+ /// Embedded transparent cursor image for the Agent cursor overlay.
6
+ enum EmbeddedCursorImage {
7
+ static let image: NSImage? = {
8
+ guard let data = Data(base64Encoded: "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") else { return nil }
9
+ return NSImage(data: data)
10
+ }()
11
+ }