@momasiku/dsh-pilot 0.5.8 → 0.5.10
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/README.md +4 -2
- package/lib/index.js +15 -5
- package/lib/scripts/_dsh-action.ps1 +29 -7
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
**Give DeepSeek Harness hands and eyes on your desktop.**
|
|
6
6
|
|
|
7
|
+
[](https://www.npmjs.com/package/@momasiku/dsh-pilot)
|
|
8
|
+
[](https://github.com/momasiku/dsh-pilot/actions/workflows/compat.yml)
|
|
7
9
|
[](LICENSE)
|
|
10
|
+
|
|
8
11
|

|
|
9
|
-
|
|
10
|
-

|
|
12
|
+

|
|
11
13
|
|
|
12
14
|
[English](#why-this-exists) · [中文说明](#中文说明)
|
|
13
15
|
|
package/lib/index.js
CHANGED
|
@@ -992,7 +992,7 @@ const POINTER_ACTIONS = new Set(['click', 'doubleClick', 'rightClick', 'middleCl
|
|
|
992
992
|
const RISKS = ['low', 'medium', 'high'];
|
|
993
993
|
const RISK_ORDER = { low: 0, medium: 1, high: 2 };
|
|
994
994
|
/** Step fields forwarded verbatim to the action helper. */
|
|
995
|
-
const STEP_FIELDS = ['x', 'y', 'toX', 'toY', 'amount', 'text', 'key', 'title', 'button'];
|
|
995
|
+
const STEP_FIELDS = ['x', 'y', 'toX', 'toY', 'amount', 'text', 'key', 'title', 'button', 'tolerant'];
|
|
996
996
|
|
|
997
997
|
const SEQUENCE_STEP_RESULT_SCHEMA = {
|
|
998
998
|
type: 'object',
|
|
@@ -1281,13 +1281,17 @@ function apply(ctx, config) {
|
|
|
1281
1281
|
type: 'string',
|
|
1282
1282
|
description: 'Case-insensitive window title or process substring; required by focus, and filters windows.'
|
|
1283
1283
|
},
|
|
1284
|
+
tolerant: {
|
|
1285
|
+
type: 'boolean',
|
|
1286
|
+
description: 'focus only: when Windows refuses to hand the window the foreground, record a note and continue instead of failing the step. Use it when the coordinates are right whichever window ends up in front.'
|
|
1287
|
+
},
|
|
1284
1288
|
capture: {
|
|
1285
1289
|
type: 'boolean',
|
|
1286
1290
|
description: 'Capture a fresh frame after the action and show it in this result. Default true.'
|
|
1287
1291
|
},
|
|
1288
1292
|
settleMs: {
|
|
1289
1293
|
type: 'integer',
|
|
1290
|
-
description: 'Milliseconds to wait before the automatic capture, so the screen can repaint. Default 750.'
|
|
1294
|
+
description: 'Milliseconds to wait before the automatic capture, so the screen can repaint. Default 750. Skipped when capture is false, unless you pass it explicitly.'
|
|
1291
1295
|
},
|
|
1292
1296
|
forceImage: {
|
|
1293
1297
|
type: 'boolean',
|
|
@@ -1338,9 +1342,15 @@ function apply(ctx, config) {
|
|
|
1338
1342
|
const wantsCapture = args.capture !== false;
|
|
1339
1343
|
if (wantsCapture) await assertImageCapableRoute(ctx, exec, 'desktop_control with capture');
|
|
1340
1344
|
|
|
1341
|
-
|
|
1345
|
+
// The settle exists so a frame is not taken mid-repaint. With no frame to
|
|
1346
|
+
// take there is nothing to wait for, and the wait is dead time: measured
|
|
1347
|
+
// 750 ms on every desktop_control call, capturing or not. An explicit
|
|
1348
|
+
// settleMs is still honoured, so a caller that wants a pause before its
|
|
1349
|
+
// own screen_view keeps it.
|
|
1350
|
+
const explicitSettle = Number.isSafeInteger(args.settleMs);
|
|
1351
|
+
const settle = explicitSettle ? args.settleMs : (wantsCapture ? config.settleMs : 0);
|
|
1342
1352
|
const params = { action: args.action, settleMs: settle };
|
|
1343
|
-
for (const field of ['x', 'y', 'toX', 'toY', 'amount', 'text', 'key', 'title', 'button']) {
|
|
1353
|
+
for (const field of ['x', 'y', 'toX', 'toY', 'amount', 'text', 'key', 'title', 'button', 'tolerant']) {
|
|
1344
1354
|
if (args[field] !== undefined && args[field] !== null) params[field] = args[field];
|
|
1345
1355
|
}
|
|
1346
1356
|
|
|
@@ -1396,7 +1406,7 @@ function apply(ctx, config) {
|
|
|
1396
1406
|
steps: {
|
|
1397
1407
|
type: 'array',
|
|
1398
1408
|
required: true,
|
|
1399
|
-
description: 'Ordered steps. Each object is one desktop_control action: {action, x, y, toX, toY, text, key, title, amount, button, settleMs, risk, riskNote}; action "wait" takes ms. Coordinates are physical screen pixels.'
|
|
1409
|
+
description: 'Ordered steps. Each object is one desktop_control action: {action, x, y, toX, toY, text, key, title, amount, button, tolerant, settleMs, risk, riskNote}; action "wait" takes ms. A focus step that Windows refuses now fails unless tolerant: true. Coordinates are physical screen pixels.'
|
|
1400
1410
|
},
|
|
1401
1411
|
risk: {
|
|
1402
1412
|
type: 'string',
|
|
@@ -304,21 +304,31 @@ switch ($action) {
|
|
|
304
304
|
}
|
|
305
305
|
}
|
|
306
306
|
'focus' {
|
|
307
|
+
# A refused hand-off used to be a note: the step reported ok and the batch
|
|
308
|
+
# carried on, so every later click and keystroke went to whatever window was
|
|
309
|
+
# actually in front. That is the one failure this plugin must not report as
|
|
310
|
+
# success, so it is an error now; tolerant keeps the old behaviour for a
|
|
311
|
+
# caller that knows the coordinates are right either way.
|
|
312
|
+
$tolerant = $false
|
|
313
|
+
$tolerantRaw = Get-Param 'tolerant'
|
|
314
|
+
if ($null -ne $tolerantRaw) { $tolerant = [bool] $tolerantRaw }
|
|
315
|
+
$label = ''
|
|
316
|
+
$target = [IntPtr]::Zero
|
|
307
317
|
if ($script:TargetHwnd -ne [IntPtr]::Zero) {
|
|
308
318
|
# An explicit handle is authoritative and works for a window hidden
|
|
309
319
|
# to the tray, which a title search cannot reach.
|
|
310
320
|
if (-not [DshInput]::IsAlive($script:TargetHwnd)) { Write-ActionError "the target window (hwnd $($script:TargetHwndText)) no longer exists" }
|
|
311
|
-
$
|
|
312
|
-
|
|
321
|
+
$target = $script:TargetHwnd
|
|
322
|
+
$label = "hwnd $($script:TargetHwndText)"
|
|
323
|
+
$null = [DshInput]::ForceForeground($target)
|
|
313
324
|
Start-Sleep -Milliseconds 220
|
|
314
325
|
} else {
|
|
315
326
|
if ([string]::IsNullOrWhiteSpace($windowTitle)) { Write-ActionError 'focus requires a title, or an hwnd' }
|
|
316
327
|
$needle = $windowTitle.ToLowerInvariant()
|
|
317
328
|
# EnumWindows, not Process.MainWindowHandle: an Electron, UWP or tray
|
|
318
329
|
# window frequently reports no main window handle at all, so a
|
|
319
|
-
# MainWindowHandle scan cannot find a window that
|
|
320
|
-
# already enumerates) happily lists.
|
|
321
|
-
$target = [IntPtr]::Zero
|
|
330
|
+
# MainWindowHandle scan cannot find a window that the windows action
|
|
331
|
+
# (which already enumerates) happily lists.
|
|
322
332
|
$fallback = [IntPtr]::Zero
|
|
323
333
|
foreach ($handle in [DshInput]::TopLevelWindows()) {
|
|
324
334
|
if (-not [DshInput]::IsWindowVisible($handle)) { continue }
|
|
@@ -335,10 +345,22 @@ switch ($action) {
|
|
|
335
345
|
}
|
|
336
346
|
if ($target -eq [IntPtr]::Zero) { $target = $fallback }
|
|
337
347
|
if ($target -eq [IntPtr]::Zero) { Write-ActionError "no visible top-level window matches '$windowTitle'; pass an hwnd if the window is hidden to the tray" }
|
|
338
|
-
$
|
|
339
|
-
|
|
348
|
+
$label = "'" + [DshInput]::WindowTitle($target) + "'"
|
|
349
|
+
$null = [DshInput]::Activate($target)
|
|
340
350
|
Start-Sleep -Milliseconds 220
|
|
341
351
|
}
|
|
352
|
+
|
|
353
|
+
# Ask the desktop, not the API. SetForegroundWindow is documented to be
|
|
354
|
+
# unreliable about its return value, and the state that decides where the
|
|
355
|
+
# next click lands is the foreground window, not what the call returned.
|
|
356
|
+
if (-not [DshInput]::IsForeground($target)) {
|
|
357
|
+
$holder = [DshInput]::ForegroundTitle()
|
|
358
|
+
if ($tolerant) {
|
|
359
|
+
$notes += "Windows would not hand focus to $label; '$holder' kept it (tolerant: continuing)."
|
|
360
|
+
} else {
|
|
361
|
+
Write-ActionError "could not bring $label to the foreground; '$holder' still holds it, so the rest of this batch would land there. Pass tolerant: true on this step if the coordinates are right either way."
|
|
362
|
+
}
|
|
363
|
+
}
|
|
342
364
|
}
|
|
343
365
|
'windows' {
|
|
344
366
|
$query = $windowTitle.ToLowerInvariant()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@momasiku/dsh-pilot",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.10",
|
|
4
4
|
"description": "Desktop vision and control for DeepSeek Harness - the whole Windows machine, any application, not browser automation: screen_view captures the live screen as an image the model can see, desktop_control drives the mouse, keyboard, and windows against the exact same pixel space; desktop_sequence runs a whole batch of actions in one call and looks once at the end.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "momasiku",
|
|
@@ -40,9 +40,9 @@
|
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"@deepseek-ai/cordis": "^4.0.2",
|
|
43
|
-
"@deepseek-ai/dsh-attachment": ">=0.1.5-rc.2 <0.2.0 || >=0.2.0-rc.1 <0.3.0-0",
|
|
44
|
-
"@deepseek-ai/dsh-llm": ">=0.1.5-rc.2 <0.2.0 || >=0.2.0-rc.1 <0.3.0-0",
|
|
45
|
-
"@deepseek-ai/dsh-tools": ">=0.1.5-rc.2 <0.2.0 || >=0.2.0-rc.1 <0.3.0-0"
|
|
43
|
+
"@deepseek-ai/dsh-attachment": ">=0.1.5-rc.2 <0.2.0 || >=0.2.0-rc.1 <0.3.0-0 || >=0.2.1-0 <0.3.0-0",
|
|
44
|
+
"@deepseek-ai/dsh-llm": ">=0.1.5-rc.2 <0.2.0 || >=0.2.0-rc.1 <0.3.0-0 || >=0.2.1-0 <0.3.0-0",
|
|
45
|
+
"@deepseek-ai/dsh-tools": ">=0.1.5-rc.2 <0.2.0 || >=0.2.0-rc.1 <0.3.0-0 || >=0.2.1-0 <0.3.0-0"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@deepseek-ai/schemastery": "^3.18.2"
|