@logictan/dsh-desktop-agent 0.1.0 → 0.1.2
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 +2 -2
- package/lib/index.js +34 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -48,8 +48,8 @@ to the `cua_driver_native__*` tools it publishes and has no driver of its own.
|
|
|
48
48
|
|
|
49
49
|
`desktop_agent({ app, goal, windowId })` resolves one window, runs the
|
|
50
50
|
observe/decide/act loop until `DONE`/`BLOCKED` or a cap is reached, and returns a
|
|
51
|
-
structured trace. `app` accepts
|
|
52
|
-
|
|
51
|
+
structured trace. `app` accepts an application name or a window title; omitting
|
|
52
|
+
it uses the frontmost window.
|
|
53
53
|
|
|
54
54
|
Only on-screen windows are eligible. A covered window cannot be captured or acted
|
|
55
55
|
on, so the tool fails with the window named rather than screenshotting whatever
|
package/lib/index.js
CHANGED
|
@@ -151,7 +151,7 @@ export function apply(ctx, config) {
|
|
|
151
151
|
'delivery — the plugin settings control that. This tool waits for the run to finish and returns a structured ' +
|
|
152
152
|
'trace of every step.',
|
|
153
153
|
parameters: {
|
|
154
|
-
app: { type: 'string', description: 'Application to drive:
|
|
154
|
+
app: { type: 'string', description: 'Application to drive: an app name or a window title. Omit to use the frontmost window.' },
|
|
155
155
|
goal: { type: 'string', description: 'What must be true when the task is finished.', required: true },
|
|
156
156
|
windowId: { type: 'integer', description: 'Exact window id from a prior listing. Omit to resolve the window from the app argument.' },
|
|
157
157
|
},
|
|
@@ -235,7 +235,12 @@ async function resolveTarget(input) {
|
|
|
235
235
|
|
|
236
236
|
const value = await dispatch('cua_driver_native__list_windows', {}, signal);
|
|
237
237
|
const payload = structured(value, 'list_windows');
|
|
238
|
-
|
|
238
|
+
// A payload that parses but carries no window array is a driver contract
|
|
239
|
+
// failure, not an empty desktop. Flattening it to [] would report the two as
|
|
240
|
+
// the same sentence, and the driver is a third-party boundary whose response
|
|
241
|
+
// shape this plugin does not control.
|
|
242
|
+
if (!Array.isArray(payload.windows)) throw new Error('desktop_agent: list_windows returned no window array.');
|
|
243
|
+
const windows = payload.windows;
|
|
239
244
|
if (windows.length === 0) throw new Error('desktop_agent: the driver listed no windows.');
|
|
240
245
|
|
|
241
246
|
if (args.windowId !== undefined) {
|
|
@@ -262,20 +267,41 @@ async function resolveTarget(input) {
|
|
|
262
267
|
}
|
|
263
268
|
|
|
264
269
|
const needle = args.app.toLowerCase();
|
|
265
|
-
const matches = onScreen.filter(
|
|
266
|
-
(window) =>
|
|
267
|
-
String(window.app_name ?? '').toLowerCase().includes(needle) ||
|
|
268
|
-
String(window.title ?? '').toLowerCase().includes(needle),
|
|
269
|
-
);
|
|
270
|
+
const matches = onScreen.filter((window) => matchesApp(window, needle));
|
|
270
271
|
if (matches.length === 0) {
|
|
272
|
+
// An app that is running but has no window on screen is a different fact
|
|
273
|
+
// from an app that is not running, and only the second one suggests
|
|
274
|
+
// launching it. The windowId path already tells them apart.
|
|
275
|
+
if (windows.some((window) => matchesApp(window, needle))) {
|
|
276
|
+
throw new Error(
|
|
277
|
+
'desktop_agent: "' + args.app + '" is open, but no window of it is on screen, so it cannot be captured or acted on.',
|
|
278
|
+
);
|
|
279
|
+
}
|
|
271
280
|
const names = [...new Set(onScreen.map((window) => window.app_name).filter(Boolean))];
|
|
272
281
|
throw new Error(
|
|
273
|
-
'desktop_agent: no on-screen window matches "' + args.app + '".
|
|
282
|
+
'desktop_agent: no on-screen window matches "' + args.app + '". On-screen apps: ' + (names.join(', ') || '(none)') + '.',
|
|
274
283
|
);
|
|
275
284
|
}
|
|
276
285
|
return targetOf(bestMatch(matches));
|
|
277
286
|
}
|
|
278
287
|
|
|
288
|
+
/**
|
|
289
|
+
* Whether a window answers to an app argument.
|
|
290
|
+
*
|
|
291
|
+
* The needle is matched against the application name and the window title,
|
|
292
|
+
* because both are things a caller can reasonably name.
|
|
293
|
+
*
|
|
294
|
+
* @param window - a window from the driver's list.
|
|
295
|
+
* @param needle - the app argument, lower-cased.
|
|
296
|
+
* @returns whether the window matches.
|
|
297
|
+
*/
|
|
298
|
+
function matchesApp(window, needle) {
|
|
299
|
+
return (
|
|
300
|
+
String(window.app_name ?? '').toLowerCase().includes(needle) ||
|
|
301
|
+
String(window.title ?? '').toLowerCase().includes(needle)
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
|
|
279
305
|
/**
|
|
280
306
|
* Choose the window to drive from the candidates an app argument matched.
|
|
281
307
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@logictan/dsh-desktop-agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "DSH desktop agent: a native-vision decision loop that drives the host desktop through the Cua Driver tools. DSH 桌面 Agent 子插件。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|