@remcp/runtime 0.2.96 → 0.2.97
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 +6 -0
- package/package.json +1 -1
- package/src/extended/desktop-linux.mjs +47 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.97 — 2026-09-22
|
|
4
|
+
|
|
5
|
+
- Native GNOME Wayland `move`, `resize`, and `move_resize` no longer trust a portal drag as proof of success.
|
|
6
|
+
- Window geometry is re-read after each gesture and must match the requested coordinates/size within a bounded tolerance; otherwise the action fails closed.
|
|
7
|
+
- `move_resize` confirms the move before computing the resize gesture. Tool names and schemas remain unchanged.
|
|
8
|
+
|
|
3
9
|
## 0.2.96 — 2026-09-22
|
|
4
10
|
|
|
5
11
|
- Keeps readable search matches when an unreadable descendant is encountered while surfacing a warning.
|
package/package.json
CHANGED
|
@@ -283,6 +283,34 @@ async function focusExplicitWaylandInputTarget(args = {}) {
|
|
|
283
283
|
return row;
|
|
284
284
|
}
|
|
285
285
|
|
|
286
|
+
function nativeWaylandGeometryMatches(row, expected = {}, tolerance = 24) {
|
|
287
|
+
for (const key of ['x','y','width','height']) {
|
|
288
|
+
if (expected[key] == null) continue;
|
|
289
|
+
const actual = Number(row?.[key]);
|
|
290
|
+
const wanted = Number(expected[key]);
|
|
291
|
+
if (!Number.isFinite(actual) || !Number.isFinite(wanted) || Math.abs(actual - wanted) > tolerance) return false;
|
|
292
|
+
}
|
|
293
|
+
return true;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
async function verifyNativeWaylandGeometry(row, expected, label) {
|
|
297
|
+
let latest = row;
|
|
298
|
+
for (let attempt = 0; attempt < 6; attempt += 1) {
|
|
299
|
+
if (attempt > 0) await new Promise(resolve => setTimeout(resolve, 120));
|
|
300
|
+
try {
|
|
301
|
+
latest = await windowMatch({ id:row.id });
|
|
302
|
+
if (nativeWaylandGeometryMatches(latest, expected)) return latest;
|
|
303
|
+
} catch {}
|
|
304
|
+
}
|
|
305
|
+
const actual = ['x','y','width','height']
|
|
306
|
+
.map(key => `${key}=${Number.isFinite(Number(latest?.[key])) ? Number(latest[key]) : 'unknown'}`)
|
|
307
|
+
.join(' ');
|
|
308
|
+
const wanted = Object.entries(expected)
|
|
309
|
+
.map(([key,value]) => `${key}=${value}`)
|
|
310
|
+
.join(' ');
|
|
311
|
+
throw new Error(`Could not verify native Wayland window ${label} for ${row.title || row.app || row.id}: wanted ${wanted}; observed ${actual}`);
|
|
312
|
+
}
|
|
313
|
+
|
|
286
314
|
async function nativeWaylandWindowAction(row, action, args) {
|
|
287
315
|
const backend = inputBackend(args);
|
|
288
316
|
if (backend === 'x11') unavailable('Native Wayland window action', 'use backend=portal for compositor-managed windows');
|
|
@@ -336,8 +364,11 @@ async function nativeWaylandWindowAction(row, action, args) {
|
|
|
336
364
|
hold_ms:80,
|
|
337
365
|
duration_ms:120,
|
|
338
366
|
});
|
|
339
|
-
|
|
340
|
-
|
|
367
|
+
const verified = await verifyNativeWaylandGeometry(row, { x, y }, 'move');
|
|
368
|
+
currentX = Number(verified.x);
|
|
369
|
+
currentY = Number(verified.y);
|
|
370
|
+
currentWidth = Number(verified.width);
|
|
371
|
+
currentHeight = Number(verified.height);
|
|
341
372
|
}
|
|
342
373
|
|
|
343
374
|
if (action === 'resize' || action === 'move_resize') {
|
|
@@ -352,7 +383,21 @@ async function nativeWaylandWindowAction(row, action, args) {
|
|
|
352
383
|
hold_ms:80,
|
|
353
384
|
duration_ms:120,
|
|
354
385
|
});
|
|
386
|
+
const verified = await verifyNativeWaylandGeometry(row, { width, height }, 'resize');
|
|
387
|
+
currentX = Number(verified.x);
|
|
388
|
+
currentY = Number(verified.y);
|
|
389
|
+
currentWidth = Number(verified.width);
|
|
390
|
+
currentHeight = Number(verified.height);
|
|
355
391
|
}
|
|
392
|
+
return jsonResult({
|
|
393
|
+
action,
|
|
394
|
+
backend:'xdg-desktop-portal',
|
|
395
|
+
id:row.id,
|
|
396
|
+
x:currentX,
|
|
397
|
+
y:currentY,
|
|
398
|
+
width:currentWidth,
|
|
399
|
+
height:currentHeight,
|
|
400
|
+
});
|
|
356
401
|
}
|
|
357
402
|
return jsonResult({ action, backend:'xdg-desktop-portal', id:row.id });
|
|
358
403
|
}
|