@anionex/dsh-computer-use 0.3.2 → 0.3.3
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 +130 -0
- package/README.md +4 -1
- package/README.zh.md +4 -1
- package/lib/client.js +1 -1
- package/lib/client.js.map +1 -1
- package/lib/config.js +37 -17
- package/lib/config.js.map +1 -1
- package/lib/confirmations.js.map +1 -1
- package/lib/exposure.js +4 -4
- package/lib/exposure.js.map +1 -1
- package/lib/index.js +5 -1
- package/lib/index.js.map +1 -1
- package/lib/leases.js.map +1 -1
- package/lib/providers/macos.js +27 -11
- package/lib/providers/macos.js.map +1 -1
- package/lib/skill.js +13 -2
- package/lib/skill.js.map +1 -1
- package/lib/tools.js +1 -1
- package/lib/tools.js.map +1 -1
- package/lib/types/client/index.d.ts +1 -1
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/config.d.ts +2 -0
- package/lib/types/config.d.ts.map +1 -1
- package/lib/types/confirmations.d.ts +1 -1
- package/lib/types/confirmations.d.ts.map +1 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/leases.d.ts +2 -1
- package/lib/types/leases.d.ts.map +1 -1
- package/lib/types/providers/macos.d.ts +0 -1
- package/lib/types/providers/macos.d.ts.map +1 -1
- package/lib/types/skill.d.ts +7 -2
- package/lib/types/skill.d.ts.map +1 -1
- package/lib/types/tools.d.ts.map +1 -1
- package/lib/types/types.d.ts +3 -1
- package/lib/types/types.d.ts.map +1 -1
- package/lib/types/web.d.ts +2 -1
- package/lib/types/web.d.ts.map +1 -1
- package/lib/types.js.map +1 -1
- package/lib/web.js +18 -8
- package/lib/web.js.map +1 -1
- package/native/macos/Sources/Helper/CursorOverlay.swift +3 -0
- package/native/macos/Sources/Helper/main.swift +35 -19
- package/native/macos/bin/dsh-computer-use-helper +0 -0
- package/native/macos/manifest.json +3 -3
- package/package.json +64 -24
- package/scripts/model-e2e.mjs +7 -3
- package/scripts/session-transcript.mjs +4 -3
- package/src/client/index.tsx +4 -2
- package/src/config.ts +40 -18
- package/src/confirmations.ts +1 -1
- package/src/exposure.ts +5 -5
- package/src/index.ts +5 -1
- package/src/leases.ts +3 -2
- package/src/providers/macos.ts +31 -11
- package/src/skill.ts +14 -2
- package/src/tools.ts +3 -2
- package/src/types.ts +2 -1
- package/src/web.ts +21 -6
package/lib/web.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web.js","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"AAAA,uDAAuD;AAIvD,OAAO,EAAE,qBAAqB,EAA2B,MAAM,2BAA2B,CAAA;AAE1F,OAAO,EACL,+BAA+B,
|
|
1
|
+
{"version":3,"file":"web.js","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"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"}
|
|
@@ -204,6 +204,9 @@ private final class CursorOverlayController: NSObject {
|
|
|
204
204
|
window.isOpaque = false
|
|
205
205
|
window.backgroundColor = .clear
|
|
206
206
|
window.hasShadow = false
|
|
207
|
+
// Target loss must remove the indicator immediately, without AppKit's
|
|
208
|
+
// panel fade leaving it visible over an unrelated foreground app.
|
|
209
|
+
window.animationBehavior = .none
|
|
207
210
|
window.ignoresMouseEvents = true
|
|
208
211
|
window.hidesOnDeactivate = false
|
|
209
212
|
window.becomesKeyOnlyIfNeeded = true
|
|
@@ -6,7 +6,7 @@ import Darwin
|
|
|
6
6
|
import Foundation
|
|
7
7
|
import ScreenCaptureKit
|
|
8
8
|
|
|
9
|
-
private let helperVersion = "0.3.
|
|
9
|
+
private let helperVersion = "0.3.3"
|
|
10
10
|
|
|
11
11
|
private struct HelperError: Error {
|
|
12
12
|
let code: String
|
|
@@ -501,22 +501,27 @@ private func captureWindow(_ snapshot: ObservationSnapshot, path: String, requir
|
|
|
501
501
|
return nil
|
|
502
502
|
}
|
|
503
503
|
let expectedId = (snapshot.windowJSON?["id"] as? NSNumber)?.uint32Value
|
|
504
|
-
let
|
|
504
|
+
let expectedFrame = (snapshot.windowJSON?["frame"] as? [String: Any]).flatMap { try? cgRect($0) }
|
|
505
505
|
let windows = content.windows.filter { $0.owningApplication?.processID == snapshot.app.processIdentifier }
|
|
506
506
|
let selected = windows.first { window in
|
|
507
|
-
if let expectedId
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
507
|
+
if let expectedId { return window.windowID == expectedId }
|
|
508
|
+
guard let expectedFrame else { return false }
|
|
509
|
+
let tolerance: CGFloat = 2
|
|
510
|
+
return abs(window.frame.minX - expectedFrame.minX) <= tolerance
|
|
511
|
+
&& abs(window.frame.minY - expectedFrame.minY) <= tolerance
|
|
512
|
+
&& abs(window.frame.width - expectedFrame.width) <= tolerance
|
|
513
|
+
&& abs(window.frame.height - expectedFrame.height) <= tolerance
|
|
514
|
+
}
|
|
511
515
|
guard let selected else {
|
|
512
|
-
if required { throw fail("COMPUTER_TARGET_UNAVAILABLE", "
|
|
516
|
+
if required { throw fail("COMPUTER_TARGET_UNAVAILABLE", "the observed window is not available for capture") }
|
|
513
517
|
return nil
|
|
514
518
|
}
|
|
519
|
+
let filter = SCContentFilter(desktopIndependentWindow: selected)
|
|
515
520
|
let configuration = SCStreamConfiguration()
|
|
516
|
-
|
|
517
|
-
configuration.
|
|
521
|
+
let pixelScale = CGFloat(filter.pointPixelScale)
|
|
522
|
+
configuration.width = max(1, Int((selected.frame.width * pixelScale).rounded()))
|
|
523
|
+
configuration.height = max(1, Int((selected.frame.height * pixelScale).rounded()))
|
|
518
524
|
configuration.showsCursor = false
|
|
519
|
-
let filter = SCContentFilter(desktopIndependentWindow: selected)
|
|
520
525
|
let image: CGImage
|
|
521
526
|
do {
|
|
522
527
|
image = try await SCScreenshotManager.captureImage(contentFilter: filter, configuration: configuration)
|
|
@@ -583,25 +588,36 @@ private func cgRect(_ frame: [String: Any]) throws -> CGRect {
|
|
|
583
588
|
|
|
584
589
|
private func windowAtPoint(app: NSRunningApplication, point: CGPoint) throws -> (windowNumber: Int64, frame: CGRect) {
|
|
585
590
|
guard let windows = CGWindowListCopyWindowInfo(
|
|
586
|
-
[.
|
|
591
|
+
[.optionAll, .excludeDesktopElements],
|
|
587
592
|
kCGNullWindowID
|
|
588
593
|
) as? [[String: Any]] else {
|
|
589
594
|
throw fail("COMPUTER_TARGET_UNAVAILABLE", "CoreGraphics window list is unavailable")
|
|
590
595
|
}
|
|
591
|
-
|
|
592
|
-
// first match is the topmost window of the selected app at the point.
|
|
593
|
-
guard let window = windows.first(where: { candidate in
|
|
596
|
+
let appWindows = windows.filter { candidate in
|
|
594
597
|
guard (candidate[kCGWindowOwnerPID as String] as? NSNumber)?.int32Value == app.processIdentifier,
|
|
595
|
-
(candidate[kCGWindowLayer as String] as? NSNumber)?.intValue == 0
|
|
596
|
-
let bounds = candidate[kCGWindowBounds as String] as? [String: Any],
|
|
597
|
-
let frame = CGRect(dictionaryRepresentation: bounds as CFDictionary),
|
|
598
|
-
frame.contains(point) else { return false }
|
|
598
|
+
(candidate[kCGWindowLayer as String] as? NSNumber)?.intValue == 0 else { return false }
|
|
599
599
|
return true
|
|
600
|
+
}
|
|
601
|
+
let containing = appWindows.filter { candidate in
|
|
602
|
+
guard let bounds = candidate[kCGWindowBounds as String] as? [String: Any],
|
|
603
|
+
let frame = CGRect(dictionaryRepresentation: bounds as CFDictionary) else { return false }
|
|
604
|
+
return frame.contains(point)
|
|
605
|
+
}
|
|
606
|
+
// optionAll can recover windows omitted by optionOnScreenOnly on some
|
|
607
|
+
// multi-display layouts. Never route pointer input to a hidden window.
|
|
608
|
+
guard let window = containing.first(where: {
|
|
609
|
+
($0[kCGWindowIsOnscreen as String] as? NSNumber)?.boolValue == true
|
|
600
610
|
}),
|
|
601
611
|
let windowNumber = (window[kCGWindowNumber as String] as? NSNumber)?.int64Value,
|
|
602
612
|
let bounds = window[kCGWindowBounds as String] as? [String: Any],
|
|
603
613
|
let frame = CGRect(dictionaryRepresentation: bounds as CFDictionary) else {
|
|
604
|
-
|
|
614
|
+
if !containing.isEmpty {
|
|
615
|
+
throw fail("COMPUTER_TARGET_UNAVAILABLE", "the selected app window contains the coordinate but CoreGraphics does not mark it on-screen")
|
|
616
|
+
}
|
|
617
|
+
if appWindows.isEmpty {
|
|
618
|
+
throw fail("COMPUTER_TARGET_UNAVAILABLE", "the selected app has no enumerable layer-zero window in CoreGraphics")
|
|
619
|
+
}
|
|
620
|
+
throw fail("COMPUTER_TARGET_UNAVAILABLE", "coordinate is outside the selected app's enumerable windows")
|
|
605
621
|
}
|
|
606
622
|
return (windowNumber, frame)
|
|
607
623
|
}
|
|
Binary file
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"helperVersion": "0.3.
|
|
4
|
-
"sourceSha256": "
|
|
3
|
+
"helperVersion": "0.3.3",
|
|
4
|
+
"sourceSha256": "b5de65a33e53689c5b490d8f6641a6577ba61a6f6f45798210b0df65bd0ced07",
|
|
5
5
|
"binary": {
|
|
6
6
|
"path": "bin/dsh-computer-use-helper",
|
|
7
|
-
"sha256": "
|
|
7
|
+
"sha256": "55325e0008d755bf2b1d408bcfd5cdb80842ec2a0fa5312da6961eb65d7d6dd3",
|
|
8
8
|
"architectures": [
|
|
9
9
|
"arm64",
|
|
10
10
|
"x86_64"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anionex/dsh-computer-use",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "Accessibility-first macOS Computer Use capability for DeepSeek Harness with stale-observation protection, app leases, confirmations, screenshots, and Web diagnostics",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek",
|
|
@@ -56,7 +56,8 @@
|
|
|
56
56
|
"cordis.patch.yml",
|
|
57
57
|
"README.md",
|
|
58
58
|
"README.zh.md",
|
|
59
|
-
"LICENSE"
|
|
59
|
+
"LICENSE",
|
|
60
|
+
"CHANGELOG.md"
|
|
60
61
|
],
|
|
61
62
|
"scripts": {
|
|
62
63
|
"native:build": "node scripts/build-native.mjs",
|
|
@@ -87,7 +88,7 @@
|
|
|
87
88
|
"platform": "web"
|
|
88
89
|
},
|
|
89
90
|
"compatibility": {
|
|
90
|
-
"dsh": ">=0.1.0-rc.8 <0.2.0 || >=0.1.1-rc.1 <0.2.0 || >=0.1.2-alpha.3 <0.2.0 || >=0.1.5-rc.1 <0.2.0",
|
|
91
|
+
"dsh": ">=0.1.0-rc.8 <0.2.0 || >=0.1.1-rc.1 <0.2.0 || >=0.1.2-alpha.3 <0.2.0 || >=0.1.5-rc.1 <0.2.0 || 0.1.7-rc.2 || 0.2.0-rc.2",
|
|
91
92
|
"dshReleases": {
|
|
92
93
|
"0.1.0-rc.8": "compatible",
|
|
93
94
|
"0.1.1-rc.1": "compatible",
|
|
@@ -97,7 +98,9 @@
|
|
|
97
98
|
"0.1.2-alpha.5": "compatible",
|
|
98
99
|
"0.1.5-alpha.1": "compatible",
|
|
99
100
|
"0.1.5-alpha.2": "compatible",
|
|
100
|
-
"0.1.5-rc.1": "compatible"
|
|
101
|
+
"0.1.5-rc.1": "compatible",
|
|
102
|
+
"0.1.7-rc.2": "compatible",
|
|
103
|
+
"0.2.0-rc.2": "compatible"
|
|
101
104
|
},
|
|
102
105
|
"profiles": [
|
|
103
106
|
"web"
|
|
@@ -105,26 +108,27 @@
|
|
|
105
108
|
}
|
|
106
109
|
},
|
|
107
110
|
"peerDependencies": {
|
|
108
|
-
"@deepseek-ai/dsh-agent": "^0.1.0-rc.6",
|
|
109
|
-
"@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.6",
|
|
110
|
-
"@deepseek-ai/dsh-brand": "^0.1.0-rc.6",
|
|
111
|
-
"@deepseek-ai/dsh-client-locale": "^0.1.0-rc.6",
|
|
112
|
-
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.0-rc.6",
|
|
113
|
-
"@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.6",
|
|
114
|
-
"@deepseek-ai/dsh-client-ui-slots": "^0.1.0-rc.6",
|
|
115
|
-
"@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.6",
|
|
116
|
-
"@deepseek-ai/dsh-llm": "^0.1.0-rc.6",
|
|
117
|
-
"@deepseek-ai/dsh-session": "^0.1.0-rc.6",
|
|
118
|
-
"@deepseek-ai/dsh-settings": "^0.1.0-rc.6",
|
|
119
|
-
"@deepseek-ai/dsh-skill": "^0.1.0-rc.6",
|
|
120
|
-
"@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.6",
|
|
121
|
-
"@deepseek-ai/dsh-subprocess": "^0.1.0-rc.6",
|
|
122
|
-
"@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.6",
|
|
123
|
-
"@deepseek-ai/dsh-tools": "^0.1.0-rc.6",
|
|
124
|
-
"@deepseek-ai/dsh-user-approval": "^0.1.0-rc.6",
|
|
111
|
+
"@deepseek-ai/dsh-agent": "^0.1.0-rc.6 || 0.1.7-rc.2 || 0.2.0-rc.2",
|
|
112
|
+
"@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.6 || 0.1.7-rc.2 || 0.2.0-rc.2",
|
|
113
|
+
"@deepseek-ai/dsh-brand": "^0.1.0-rc.6 || 0.1.7-rc.2 || 0.2.0-rc.2",
|
|
114
|
+
"@deepseek-ai/dsh-client-locale": "^0.1.0-rc.6 || 0.1.7-rc.2 || 0.2.0-rc.2",
|
|
115
|
+
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.0-rc.6 || 0.1.7-rc.2 || 0.2.0-rc.2",
|
|
116
|
+
"@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.6 || 0.1.7-rc.2 || 0.2.0-rc.2",
|
|
117
|
+
"@deepseek-ai/dsh-client-ui-slots": "^0.1.0-rc.6 || 0.1.7-rc.2 || 0.2.0-rc.2",
|
|
118
|
+
"@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.6 || 0.1.7-rc.2 || 0.2.0-rc.2",
|
|
119
|
+
"@deepseek-ai/dsh-llm": "^0.1.0-rc.6 || 0.1.7-rc.2 || 0.2.0-rc.2",
|
|
120
|
+
"@deepseek-ai/dsh-session": "^0.1.0-rc.6 || 0.1.7-rc.2 || 0.2.0-rc.2",
|
|
121
|
+
"@deepseek-ai/dsh-settings": "^0.1.0-rc.6 || 0.1.7-rc.2 || 0.2.0-rc.2",
|
|
122
|
+
"@deepseek-ai/dsh-skill": "^0.1.0-rc.6 || 0.1.7-rc.2 || 0.2.0-rc.2",
|
|
123
|
+
"@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.6 || 0.1.7-rc.2 || 0.2.0-rc.2",
|
|
124
|
+
"@deepseek-ai/dsh-subprocess": "^0.1.0-rc.6 || 0.1.7-rc.2 || 0.2.0-rc.2",
|
|
125
|
+
"@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.6 || 0.1.7-rc.2 || 0.2.0-rc.2",
|
|
126
|
+
"@deepseek-ai/dsh-tools": "^0.1.0-rc.6 || 0.1.7-rc.2 || 0.2.0-rc.2",
|
|
127
|
+
"@deepseek-ai/dsh-user-approval": "^0.1.0-rc.6 || 0.1.7-rc.2 || 0.2.0-rc.2",
|
|
125
128
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
126
129
|
"react": "^18.2.0",
|
|
127
|
-
"@deepseek-ai/schemastery": "^3.18.1"
|
|
130
|
+
"@deepseek-ai/schemastery": "^3.18.1",
|
|
131
|
+
"@deepseek-ai/dsh-util-values": "^0.1.0-rc.6 || 0.2.0-rc.2"
|
|
128
132
|
},
|
|
129
133
|
"peerDependenciesMeta": {
|
|
130
134
|
"@deepseek-ai/dsh-host-webserver": {
|
|
@@ -136,10 +140,46 @@
|
|
|
136
140
|
"@types/react": "~18.3.1",
|
|
137
141
|
"@types/react-dom": "~18.3.0",
|
|
138
142
|
"typescript": "^6.0.3",
|
|
139
|
-
"vitest": "^4.1.10"
|
|
143
|
+
"vitest": "^4.1.10",
|
|
144
|
+
"@deepseek-ai/dsh-agent": "0.2.0-rc.2",
|
|
145
|
+
"@deepseek-ai/dsh-api-remotes": "0.2.0-rc.2",
|
|
146
|
+
"@deepseek-ai/dsh-brand": "0.2.0-rc.2",
|
|
147
|
+
"@deepseek-ai/dsh-client-locale": "0.2.0-rc.2",
|
|
148
|
+
"@deepseek-ai/dsh-client-ui-primitives": "0.2.0-rc.2",
|
|
149
|
+
"@deepseek-ai/dsh-client-ui-settings": "0.2.0-rc.2",
|
|
150
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.2.0-rc.2",
|
|
151
|
+
"@deepseek-ai/dsh-host-webserver": "0.2.0-rc.2",
|
|
152
|
+
"@deepseek-ai/dsh-llm": "0.2.0-rc.2",
|
|
153
|
+
"@deepseek-ai/dsh-session": "0.2.0-rc.2",
|
|
154
|
+
"@deepseek-ai/dsh-settings": "0.2.0-rc.2",
|
|
155
|
+
"@deepseek-ai/dsh-skill": "0.2.0-rc.2",
|
|
156
|
+
"@deepseek-ai/dsh-storage-domain": "0.2.0-rc.2",
|
|
157
|
+
"@deepseek-ai/dsh-subprocess": "0.2.0-rc.2",
|
|
158
|
+
"@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2",
|
|
159
|
+
"@deepseek-ai/dsh-tools": "0.2.0-rc.2",
|
|
160
|
+
"@deepseek-ai/dsh-user-approval": "0.2.0-rc.2",
|
|
161
|
+
"@deepseek-ai/cordis": "4.0.4",
|
|
162
|
+
"@deepseek-ai/schemastery": "3.18.4",
|
|
163
|
+
"@deepseek-ai/dsh-util-values": "0.2.0-rc.2",
|
|
164
|
+
"@deepseek-ai/dsh-client-ui-renderer": "0.2.0-rc.2",
|
|
165
|
+
"@deepseek-ai/dsh-client-connection": "0.2.0-rc.2",
|
|
166
|
+
"@deepseek-ai/dsh-scope": "0.2.0-rc.2",
|
|
167
|
+
"@deepseek-ai/dsh-storage": "0.2.0-rc.2",
|
|
168
|
+
"@deepseek-ai/cosmokit": "1.8.5",
|
|
169
|
+
"@deepseek-ai/dsh-credentials": "0.2.0-rc.2",
|
|
170
|
+
"@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2",
|
|
171
|
+
"@deepseek-ai/dsh-util-crypto": "0.2.0-rc.2",
|
|
172
|
+
"@deepseek-ai/dsh-timeout": "0.2.0-rc.2",
|
|
173
|
+
"@deepseek-ai/dsh-sandbox": "0.2.0-rc.2",
|
|
174
|
+
"@deepseek-ai/dsh-http-proxy": "0.2.0-rc.2",
|
|
175
|
+
"@deepseek-ai/cordis-plugin-loader": "1.0.5",
|
|
176
|
+
"@deepseek-ai/dsh-util-workspace-path": "0.2.0-rc.2",
|
|
177
|
+
"@deepseek-ai/dsh-client-store": "0.2.0-rc.2",
|
|
178
|
+
"@deepseek-ai/dsh-util-code-language": "0.2.0-rc.2",
|
|
179
|
+
"@deepseek-ai/dsh-deque": "0.2.0-rc.2"
|
|
140
180
|
},
|
|
141
181
|
"dependencies": {
|
|
142
|
-
"zod": "
|
|
182
|
+
"zod": "4.4.3"
|
|
143
183
|
},
|
|
144
184
|
"license": "MIT"
|
|
145
185
|
}
|
package/scripts/model-e2e.mjs
CHANGED
|
@@ -45,8 +45,8 @@ function externalCommand(command, args) {
|
|
|
45
45
|
// A long-running Node harness can leave DSH without its internal ESM loader.
|
|
46
46
|
// A login shell matches the real CLI entry and keeps profile package resolution isolated.
|
|
47
47
|
return command === 'dsh' && process.platform === 'darwin'
|
|
48
|
-
? { command: '/bin/bash', args: ['-lc', 'exec
|
|
49
|
-
: { command, args }
|
|
48
|
+
? { command: '/bin/bash', args: ['-lc', 'exec "$@"', 'dsh', process.env.DSH_TEST_CLI ?? 'dsh', ...args] }
|
|
49
|
+
: { command: command === 'dsh' ? process.env.DSH_TEST_CLI ?? command : command, args }
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
async function runCommand(name, command, args, options = {}) {
|
|
@@ -180,6 +180,8 @@ async function realModelWorkflow() {
|
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
const tarball = await findTarball(packing)
|
|
183
|
+
await mkdir(join(home, 'profiles', 'headless'), { recursive: true })
|
|
184
|
+
await writeFile(join(home, 'profiles', 'headless', 'pnpm-workspace.yaml'), 'nodeLinker: hoisted\nautoInstallPeers: false\n')
|
|
183
185
|
await runCommand(
|
|
184
186
|
'install dsh-computer-use tarball',
|
|
185
187
|
'dsh',
|
|
@@ -215,6 +217,8 @@ async function realModelWorkflow() {
|
|
|
215
217
|
].join('\n'))
|
|
216
218
|
|
|
217
219
|
const prompt = `/computer-use\n\nUse the dsh-computer-use capability to operate the running deterministic macOS fixture whose bundle id is ${BUNDLE_ID}. Load the Skill, list running applications, select the exact fixture process, observe it with a required screenshot and full Accessibility state, locate the element labelled "Targeted pointer probe", and click that current element using its observation id and element index with allowCoordinateFallback=true. Confirm from the fresh post-action observation that the status reads "Status: pointer click". Use only the focused computer-use Tools for UI observation and input; do not use shell, AppleScript, JXA, direct file edits, or coordinate guessing. Finish immediately after confirming the pointer-click state.`
|
|
220
|
+
const hostVersion = await runCommand('target DSH version', 'dsh', ['--version'])
|
|
221
|
+
const defaultBaseURL = hostVersion.stdout.includes('0.2.') ? 'https://api.deepseek.com/anthropic' : 'https://api.deepseek.com/v1'
|
|
218
222
|
const result = await runCommand(
|
|
219
223
|
'DeepSeek V4 computer-use fixture workflow',
|
|
220
224
|
'dsh',
|
|
@@ -226,7 +230,7 @@ async function realModelWorkflow() {
|
|
|
226
230
|
DSH_TELEMETRY_DISABLED: '1',
|
|
227
231
|
DSH_PERMISSION_MODE: 'workspace-write',
|
|
228
232
|
DEEPSEEK_API_KEY: requiredEnvironment('DEEPSEEK_API_KEY'),
|
|
229
|
-
DEEPSEEK_BASE_URL: process.env.DEEPSEEK_BASE_URL?.trim() ||
|
|
233
|
+
DEEPSEEK_BASE_URL: process.env.DEEPSEEK_BASE_URL?.trim() || defaultBaseURL,
|
|
230
234
|
},
|
|
231
235
|
timeoutMs: 600_000,
|
|
232
236
|
},
|
|
@@ -53,7 +53,7 @@ async function sessionLogs(directory) {
|
|
|
53
53
|
for (const entry of await readdir(directory, { withFileTypes: true }).catch(() => [])) {
|
|
54
54
|
const path = join(directory, entry.name)
|
|
55
55
|
if (entry.isDirectory()) result.push(...await sessionLogs(path))
|
|
56
|
-
else if (entry.isFile() && (
|
|
56
|
+
else if (entry.isFile() && /^session(?:\.v\d+)?\.jsonl(?:\.zstd)?$/u.test(entry.name)) result.push(path)
|
|
57
57
|
}
|
|
58
58
|
return result
|
|
59
59
|
}
|
|
@@ -71,8 +71,9 @@ function resultValue(event) {
|
|
|
71
71
|
const outer = event?.data?.message?.content
|
|
72
72
|
if (!Array.isArray(outer)) return undefined
|
|
73
73
|
for (const block of outer) {
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
// Session v4 stores tool-role text directly; earlier logs wrap it.
|
|
75
|
+
const contents = block?.type === 'tool-result' && Array.isArray(block.content) ? block.content : [block]
|
|
76
|
+
for (const content of contents) {
|
|
76
77
|
if (content?.type !== 'text' || typeof content.text !== 'string') continue
|
|
77
78
|
try { return JSON.parse(content.text) }
|
|
78
79
|
catch { return undefined }
|
package/src/client/index.tsx
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import { useEffect, useState, useSyncExternalStore, type ReactNode } from 'react'
|
|
4
4
|
import { Button, Input } from '@deepseek-ai/dsh-client-ui-primitives'
|
|
5
|
-
import type { ClientContext } from '@deepseek-ai/
|
|
5
|
+
import type { Context as ClientContext } from '@deepseek-ai/cordis'
|
|
6
|
+
import type {} from '@deepseek-ai/dsh-client-ui-renderer/client'
|
|
7
|
+
import type {} from '@deepseek-ai/dsh-client-connection/client'
|
|
6
8
|
import type {} from '@deepseek-ai/dsh-api-remotes/client'
|
|
7
9
|
import type {} from '@deepseek-ai/dsh-client-ui-settings/client'
|
|
8
10
|
import type {} from '@deepseek-ai/dsh-client-locale/client'
|
|
@@ -561,7 +563,7 @@ export function apply(ctx: ClientContext): void {
|
|
|
561
563
|
const controller = new ComputerUseSettingsController()
|
|
562
564
|
ctx.effect(() => {
|
|
563
565
|
const disposers = [
|
|
564
|
-
ctx.remote.$on('settings/document-updated', ns => { if (ns === NS) controller.refreshIfLoaded() }),
|
|
566
|
+
ctx.remote.$on('settings/document-updated', (ns: string) => { if (ns === NS) controller.refreshIfLoaded() }),
|
|
565
567
|
ctx.on('connection/reset', () => { controller.refreshIfLoaded() }),
|
|
566
568
|
]
|
|
567
569
|
return () => { for (const dispose of disposers) dispose() }
|
package/src/config.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import z from '@deepseek-ai/schemastery'
|
|
4
4
|
import type Schema from '@deepseek-ai/schemastery'
|
|
5
|
+
import * as SettingsModule from '@deepseek-ai/dsh-settings'
|
|
5
6
|
import type { SettingsNamespace } from '@deepseek-ai/dsh-settings'
|
|
6
7
|
import { ComputerUseError } from './errors.ts'
|
|
7
8
|
|
|
@@ -60,23 +61,44 @@ export interface ComputerUseConfig {
|
|
|
60
61
|
grants?: ComputerUseAppGrant[]
|
|
61
62
|
}
|
|
62
63
|
|
|
64
|
+
/** DSH 0.1.7 derives editable Settings fields from volatile Config fields.
|
|
65
|
+
* Legacy Settings can coexist with a newer Schemastery installation. Only
|
|
66
|
+
* enable references when the host Settings service uses Config-derived forms.
|
|
67
|
+
*/
|
|
68
|
+
function live<T>(field: Schema<T>): Schema<T> {
|
|
69
|
+
const candidate = field as Schema<T> & { volatile?: () => Schema<T> }
|
|
70
|
+
return 'SettingsForms' in SettingsModule && typeof candidate.volatile === 'function'
|
|
71
|
+
? candidate.volatile() as unknown as Schema<T>
|
|
72
|
+
: field
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Read the newer Loader's stable references without changing the legacy shape. */
|
|
76
|
+
export function readComputerUseConfig(config: ComputerUseConfig): ComputerUseConfig {
|
|
77
|
+
return Object.fromEntries(Object.entries(config).map(([key, value]) => [
|
|
78
|
+
key,
|
|
79
|
+
value !== null && typeof value === 'object' && 'get' in value && typeof value.get === 'function'
|
|
80
|
+
? value.get()
|
|
81
|
+
: value,
|
|
82
|
+
])) as ComputerUseConfig
|
|
83
|
+
}
|
|
84
|
+
|
|
63
85
|
/** Configuration schema used by Cordis and the Settings provider. */
|
|
64
86
|
export const Config: Schema<ComputerUseConfig> = z.object({
|
|
65
|
-
observationTtlMs: z.number().default(0),
|
|
66
|
-
confirmationTtlMs: z.number().default(300000),
|
|
67
|
-
actionTimeoutMs: z.number().default(15000),
|
|
68
|
-
settleMs: z.number().default(250),
|
|
69
|
-
maxSettleMs: z.number().default(5000),
|
|
70
|
-
maxNodes: z.number().default(500),
|
|
71
|
-
maxDepth: z.number().default(14),
|
|
72
|
-
maxTextBytes: z.number().default(64000),
|
|
73
|
-
maxScreenshotBytes: z.number().default(33554432),
|
|
74
|
-
artifactRoot: z.string().default('.dsh-computer-use/artifacts'),
|
|
75
|
-
helper: z.object({
|
|
87
|
+
observationTtlMs: live(z.number().default(0)),
|
|
88
|
+
confirmationTtlMs: live(z.number().default(300000)),
|
|
89
|
+
actionTimeoutMs: live(z.number().default(15000)),
|
|
90
|
+
settleMs: live(z.number().default(250)),
|
|
91
|
+
maxSettleMs: live(z.number().default(5000)),
|
|
92
|
+
maxNodes: live(z.number().default(500)),
|
|
93
|
+
maxDepth: live(z.number().default(14)),
|
|
94
|
+
maxTextBytes: live(z.number().default(64000)),
|
|
95
|
+
maxScreenshotBytes: live(z.number().default(33554432)),
|
|
96
|
+
artifactRoot: live(z.string().default('.dsh-computer-use/artifacts')),
|
|
97
|
+
helper: live(z.object({
|
|
76
98
|
path: z.string(),
|
|
77
99
|
allowSourceBuild: z.boolean().default(false),
|
|
78
|
-
}),
|
|
79
|
-
interaction: z.object({
|
|
100
|
+
})),
|
|
101
|
+
interaction: live(z.object({
|
|
80
102
|
focusPolicy: z.union(['preserve', 'activate']).default('preserve'),
|
|
81
103
|
keyboardPolicy: z.union(['preserve', 'activate']).default('preserve'),
|
|
82
104
|
pointerInputPolicy: z.union(['deny', 'targeted']).default('targeted'),
|
|
@@ -86,14 +108,14 @@ export const Config: Schema<ComputerUseConfig> = z.object({
|
|
|
86
108
|
cursorAccelerationPxPerSecondSquared: z.number().default(6000),
|
|
87
109
|
cursorClickDelayMs: z.number().default(90),
|
|
88
110
|
cursorAutoHideMs: z.number().default(0),
|
|
89
|
-
}),
|
|
90
|
-
allowAllApps: z.boolean().default(false),
|
|
91
|
-
grants: z.array(z.object({
|
|
111
|
+
})),
|
|
112
|
+
allowAllApps: live(z.boolean().default(false)),
|
|
113
|
+
grants: live(z.array(z.object({
|
|
92
114
|
bundleId: z.string(),
|
|
93
115
|
read: z.boolean().default(false),
|
|
94
116
|
control: z.boolean().default(false),
|
|
95
|
-
})).default([]),
|
|
96
|
-
})
|
|
117
|
+
})).default([])),
|
|
118
|
+
}) as unknown as Schema<ComputerUseConfig>
|
|
97
119
|
|
|
98
120
|
/** Fully defaulted configuration consumed at runtime. */
|
|
99
121
|
export interface ResolvedComputerUseConfig {
|
package/src/confirmations.ts
CHANGED
|
@@ -48,7 +48,7 @@ export class ComputerConfirmationManager {
|
|
|
48
48
|
agent: Agent,
|
|
49
49
|
app: ComputerAppIdentity,
|
|
50
50
|
request: ComputerConfirmRequest,
|
|
51
|
-
callId: import('@deepseek-ai/dsh-
|
|
51
|
+
callId: import('@deepseek-ai/dsh-tools').ToolRunContext['callId'] | undefined,
|
|
52
52
|
signal: AbortSignal,
|
|
53
53
|
): Promise<ComputerConfirmation> {
|
|
54
54
|
if (approvalPolicy(this.ctx, agent) === 'never') {
|
package/src/exposure.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type { ContentBlock } from '@deepseek-ai/dsh-llm'
|
|
|
5
5
|
import type { Session } from '@deepseek-ai/dsh-session'
|
|
6
6
|
import { defineTool, type ToolDefinition } from '@deepseek-ai/dsh-tools'
|
|
7
7
|
import type { Context } from '@deepseek-ai/cordis'
|
|
8
|
-
import { COMPUTER_USE_SKILL_CONTENT, COMPUTER_USE_SKILL_NAME } from './skill.ts'
|
|
8
|
+
import { COMPUTER_USE_SKILL_CONTENT, COMPUTER_USE_SKILL_NAME, COMPUTER_USE_SKILL_NAMES } from './skill.ts'
|
|
9
9
|
|
|
10
10
|
/** One global bootstrap retained until the current Agent loads the Skill. */
|
|
11
11
|
export const COMPUTER_USE_ACTIVATE = 'computer_use_activate'
|
|
@@ -60,7 +60,7 @@ function adHocOcrCommand(value: unknown): boolean {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
function isSkillArguments(value: unknown): boolean {
|
|
63
|
-
return isRecord(value) && value.name
|
|
63
|
+
return isRecord(value) && COMPUTER_USE_SKILL_NAMES.has(value.name as string)
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
function nativeSkillCall(raw: string): boolean {
|
|
@@ -76,7 +76,7 @@ function containsSkillContent(blocks: readonly unknown[]): boolean {
|
|
|
76
76
|
|
|
77
77
|
function isSkillResult(value: unknown): boolean {
|
|
78
78
|
return isRecord(value)
|
|
79
|
-
&& value.name
|
|
79
|
+
&& COMPUTER_USE_SKILL_NAMES.has(value.name as string)
|
|
80
80
|
&& value.content === COMPUTER_USE_SKILL_CONTENT
|
|
81
81
|
}
|
|
82
82
|
|
|
@@ -96,12 +96,12 @@ export function hasLoadedComputerUseSkill(session: Session): boolean {
|
|
|
96
96
|
const nativeCalls = new Set<string>()
|
|
97
97
|
const events = typeof (session as any).snapshotEvents === 'function'
|
|
98
98
|
? (session as any).snapshotEvents()
|
|
99
|
-
: session.events ?? []
|
|
99
|
+
: (session as unknown as { events?: readonly import('@deepseek-ai/dsh-session').SessionEvent[] }).events ?? []
|
|
100
100
|
for (const event of events) {
|
|
101
101
|
if (event.type === 'user/message') {
|
|
102
102
|
const source = event.data.source
|
|
103
103
|
if (source.kind === 'skill-invocation'
|
|
104
|
-
&& source.name
|
|
104
|
+
&& COMPUTER_USE_SKILL_NAMES.has(source.name)
|
|
105
105
|
&& containsSkillContent(event.data.content)) return true
|
|
106
106
|
continue
|
|
107
107
|
}
|
package/src/index.ts
CHANGED
|
@@ -8,7 +8,7 @@ import type {} from '@deepseek-ai/dsh-tools'
|
|
|
8
8
|
import { Config, type ComputerUseConfig } from './config.ts'
|
|
9
9
|
import { ComputerUseExposure } from './exposure.ts'
|
|
10
10
|
import { MacOSComputerUseProvider } from './providers/macos.ts'
|
|
11
|
-
import { COMPUTER_USE_SKILL } from './skill.ts'
|
|
11
|
+
import { COMPUTER_USE_SKILL, LEGACY_COMPUTER_USE_SKILL } from './skill.ts'
|
|
12
12
|
import { createComputerUseTools } from './tools.ts'
|
|
13
13
|
import { installComputerUseWeb } from './web.ts'
|
|
14
14
|
|
|
@@ -22,14 +22,17 @@ export function installComputerUseConsumer(ctx: Context): () => void {
|
|
|
22
22
|
const exposure = new ComputerUseExposure(ctx, () => createComputerUseTools(ctx.computerUse))
|
|
23
23
|
let activation: (() => void) | undefined
|
|
24
24
|
let skill: (() => void) | undefined
|
|
25
|
+
let legacySkill: (() => void) | undefined
|
|
25
26
|
let exposureDispose: (() => void) | undefined
|
|
26
27
|
try {
|
|
27
28
|
activation = ctx.tools.register(exposure.activationTool)
|
|
28
29
|
skill = ctx.skills.register(COMPUTER_USE_SKILL)
|
|
30
|
+
legacySkill = ctx.skills.register(LEGACY_COMPUTER_USE_SKILL)
|
|
29
31
|
exposureDispose = exposure.install()
|
|
30
32
|
installComputerUseWeb(ctx)
|
|
31
33
|
} catch (error) {
|
|
32
34
|
exposureDispose?.()
|
|
35
|
+
legacySkill?.()
|
|
33
36
|
skill?.()
|
|
34
37
|
activation?.()
|
|
35
38
|
throw error
|
|
@@ -37,6 +40,7 @@ export function installComputerUseConsumer(ctx: Context): () => void {
|
|
|
37
40
|
return () => {
|
|
38
41
|
exposureDispose?.()
|
|
39
42
|
activation?.()
|
|
43
|
+
legacySkill?.()
|
|
40
44
|
skill?.()
|
|
41
45
|
}
|
|
42
46
|
}
|
package/src/leases.ts
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import { z } from 'zod'
|
|
4
4
|
import type { Agent } from '@deepseek-ai/dsh-agent'
|
|
5
|
-
import type {
|
|
5
|
+
import type { ToolRunContext } from '@deepseek-ai/dsh-tools'
|
|
6
|
+
type CallId = ToolRunContext['callId']
|
|
6
7
|
import type { SessionEvent, SessionHeader, SessionId } from '@deepseek-ai/dsh-session'
|
|
7
8
|
import { defineDomain, domainTable } from '@deepseek-ai/dsh-storage-domain'
|
|
8
9
|
import type { KvTable } from '@deepseek-ai/dsh-storage-domain'
|
|
@@ -187,7 +188,7 @@ export class ComputerLeaseManager {
|
|
|
187
188
|
await this.prepareStorage()
|
|
188
189
|
const sessionEvents = typeof (agent.session as any).snapshotEvents === 'function'
|
|
189
190
|
? (agent.session as any).snapshotEvents()
|
|
190
|
-
: agent.session.events ?? []
|
|
191
|
+
: (agent.session as unknown as { events?: readonly SessionEvent[] }).events ?? []
|
|
191
192
|
const turn = currentTurn(sessionEvents)
|
|
192
193
|
if (turn === undefined) {
|
|
193
194
|
throw new ComputerUseError('COMPUTER_PERMISSION_REQUIRED', `${scope} access for ${app.name} must be requested inside an open Agent turn`)
|
package/src/providers/macos.ts
CHANGED
|
@@ -21,6 +21,7 @@ import type {
|
|
|
21
21
|
import {
|
|
22
22
|
Config,
|
|
23
23
|
COMPUTER_USE_SETTINGS_NAMESPACE,
|
|
24
|
+
readComputerUseConfig,
|
|
24
25
|
resolveConfig,
|
|
25
26
|
type ComputerUseConfig,
|
|
26
27
|
type ResolvedComputerUseConfig,
|
|
@@ -253,21 +254,26 @@ export class MacOSComputerUseProvider extends ComputerUseService {
|
|
|
253
254
|
static inject = ['subprocess', 'approval', 'settings', 'sessions', 'agents']
|
|
254
255
|
static Config = Config
|
|
255
256
|
|
|
256
|
-
private readonly settings
|
|
257
|
-
|
|
258
257
|
constructor(ctx: Context, config: ComputerUseConfig = {}) {
|
|
259
|
-
const
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
258
|
+
const legacySettings = ctx.settings as typeof ctx.settings & {
|
|
259
|
+
register?: (ns: typeof COMPUTER_USE_SETTINGS_NAMESPACE, schema: typeof Config, options: object) => {
|
|
260
|
+
get(): ComputerUseConfig
|
|
261
|
+
watch(listener: (value: ComputerUseConfig) => Promise<void>): () => void
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
const settings = typeof legacySettings.register === 'function'
|
|
265
|
+
? legacySettings.register(COMPUTER_USE_SETTINGS_NAMESPACE, Config, {
|
|
266
|
+
base: config,
|
|
267
|
+
applies: 'live',
|
|
268
|
+
validate: (value: ComputerUseConfig) => { resolveConfig(value) },
|
|
269
|
+
})
|
|
270
|
+
: undefined
|
|
271
|
+
const resolved = resolveConfig(settings?.get() ?? readComputerUseConfig(config))
|
|
265
272
|
super(ctx, createBackend(ctx, resolved), resolved)
|
|
266
|
-
this.settings = settings
|
|
267
273
|
if (process.platform !== 'darwin') {
|
|
268
274
|
ctx.logger.warn('dsh-computer-use: supports macOS only; Computer Use Tools are disabled on %s', process.platform)
|
|
269
275
|
}
|
|
270
|
-
|
|
276
|
+
const reconfigure = async (next: ComputerUseConfig): Promise<void> => {
|
|
271
277
|
const candidate = resolveConfig(next)
|
|
272
278
|
const backend = createBackend(ctx, candidate)
|
|
273
279
|
try {
|
|
@@ -276,7 +282,21 @@ export class MacOSComputerUseProvider extends ComputerUseService {
|
|
|
276
282
|
await backend.dispose()
|
|
277
283
|
throw error
|
|
278
284
|
}
|
|
279
|
-
}
|
|
285
|
+
}
|
|
286
|
+
if (settings) {
|
|
287
|
+
ctx.effect(() => settings.watch(reconfigure), 'dsh-computer-use: Settings watch')
|
|
288
|
+
} else {
|
|
289
|
+
// DSH 0.1.7 projects Settings from Config and commits volatile fields in
|
|
290
|
+
// place. The Loader emits this event after its references have changed.
|
|
291
|
+
ctx.effect(() => {
|
|
292
|
+
const onVolatileUpdate = ctx.on as unknown as (name: string, listener: () => void) => () => void
|
|
293
|
+
return onVolatileUpdate.call(ctx, 'loader/volatile-update', () => {
|
|
294
|
+
void reconfigure(readComputerUseConfig(config)).catch(error => {
|
|
295
|
+
ctx.logger.warn('dsh-computer-use: live config update failed: %s', error)
|
|
296
|
+
})
|
|
297
|
+
})
|
|
298
|
+
}, 'dsh-computer-use: Loader volatile update')
|
|
299
|
+
}
|
|
280
300
|
ctx.effect(() => ctx.on('agent/disposed', ({ agent }) => { this.releaseAgent(agent) }), 'dsh-computer-use: Agent cleanup')
|
|
281
301
|
}
|
|
282
302
|
|