newmark-agent 0.6.4 → 0.6.8
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/config.example.json +13 -3
- package/dist/cli-commands.d.ts +1 -1
- package/dist/cli-commands.js +54 -3
- package/dist/cli-discovery.js +3 -0
- package/dist/conversation-utility-host.bundle.cjs +4472 -1767
- package/dist/conversation-utility-host.js +94 -7
- package/dist/core/agent.d.ts +126 -12
- package/dist/core/agent.js +785 -172
- package/dist/core/agentKernelRunner.d.ts +7 -1
- package/dist/core/agentKernelRunner.js +160 -20
- package/dist/core/autoRouter.d.ts +49 -44
- package/dist/core/autoRouter.js +117 -302
- package/dist/core/computerUseSession.js +1 -1
- package/dist/core/config.js +27 -11
- package/dist/core/continuation/contracts.d.ts +1 -1
- package/dist/core/continuation/store.d.ts +91 -1
- package/dist/core/continuation/store.js +291 -61
- package/dist/core/conversationKernel.d.ts +49 -7
- package/dist/core/conversationKernel.js +303 -51
- package/dist/core/conversationStateDocument.d.ts +18 -0
- package/dist/core/conversationStateDocument.js +88 -0
- package/dist/core/conversationVisualBudget.d.ts +74 -0
- package/dist/core/conversationVisualBudget.js +153 -0
- package/dist/core/electronUtilityAgentClient.d.ts +3 -2
- package/dist/core/electronUtilityAgentClient.js +32 -8
- package/dist/core/electronUtilityRuntimePool.d.ts +28 -3
- package/dist/core/electronUtilityRuntimePool.js +93 -24
- package/dist/core/fileWriteObservation.d.ts +41 -0
- package/dist/core/fileWriteObservation.js +454 -0
- package/dist/core/hostRuntimeHooks.d.ts +23 -0
- package/dist/core/hostRuntimeHooks.js +17 -0
- package/dist/core/jevDecision.d.ts +144 -0
- package/dist/core/jevDecision.js +226 -0
- package/dist/core/memoryProbe.d.ts +24 -0
- package/dist/core/memoryProbe.js +104 -0
- package/dist/core/mobilePairing.d.ts +7 -1
- package/dist/core/mobilePairing.js +9 -1
- package/dist/core/performanceDiagnostics.d.ts +1 -1
- package/dist/core/routeDecisionValidator.d.ts +86 -0
- package/dist/core/routeDecisionValidator.js +249 -0
- package/dist/core/routeEligibility.d.ts +52 -0
- package/dist/core/routeEligibility.js +108 -0
- package/dist/core/runtimeMemoryBudget.d.ts +6 -0
- package/dist/core/runtimeMemoryBudget.js +12 -0
- package/dist/core/toolPolicy.d.ts +1 -1
- package/dist/core/toolPolicy.js +1 -1
- package/dist/core/utilityAgentProtocol.d.ts +8 -10
- package/dist/core/utilityHostToolRouter.js +2 -0
- package/dist/core/visualDownscale.d.ts +6 -0
- package/dist/core/visualDownscale.js +137 -0
- package/dist/core/wslAgentClient.d.ts +1 -2
- package/dist/core/wslAgentClient.js +0 -8
- package/dist/core/wslAgentProtocol.d.ts +1 -10
- package/dist/core/wslAgentRuntimePool.d.ts +1 -3
- package/dist/core/wslAgentRuntimePool.js +17 -22
- package/dist/llm/provider.d.ts +3 -1
- package/dist/llm/provider.js +53 -9
- package/dist/main.js +107 -30
- package/dist/preload.js +3 -1
- package/dist/server.js +30 -18
- package/dist/tools/computerUse.d.ts +6 -0
- package/dist/tools/computerUse.js +406 -21
- package/dist/tools/computerUsePowerShellHost.d.ts +6 -1
- package/dist/tools/computerUsePowerShellHost.js +105 -31
- package/dist/tools/index.d.ts +3 -4
- package/dist/tools/index.js +146 -66
- package/dist/tui/src/adapters/core-runtime-adapter.js +13 -1
- package/dist/tui/src/i18n.js +12 -1
- package/dist/tui/src/render.js +9 -2
- package/dist/tui/src/settings-schema.js +19 -0
- package/dist/tui/src/state.js +69 -1
- package/dist/ui/index.html +651 -233
- package/dist/ui/lucide-sprite.svg +0 -8
- package/dist/wsl-agent-host.bundle.cjs +4302 -1767
- package/dist/wsl-agent-host.js +0 -3
- package/package.json +39 -10
|
@@ -68,6 +68,7 @@ const DEFAULT_CAPTURE_MAX_HEIGHT = 960;
|
|
|
68
68
|
const MIN_CAPTURE_MAX_WIDTH = 320;
|
|
69
69
|
const MIN_CAPTURE_MAX_HEIGHT = 240;
|
|
70
70
|
const MAX_CAPTURE_DIMENSION = 2048;
|
|
71
|
+
const MAX_SPARSE_WAIT_MS = 5000;
|
|
71
72
|
let lastScreenshotCleanupAt = 0;
|
|
72
73
|
function ephemeralScreenshotPath(kind, directory = tempScreenshotDir(), createdAt = Date.now(), ownerPid = process.pid, suffix = crypto.randomBytes(4).toString('hex')) {
|
|
73
74
|
const pid = Math.max(1, Math.floor(Number(ownerPid) || process.pid));
|
|
@@ -210,6 +211,172 @@ function jpegCaptureScript(outPath, boundsScript, requestedMaxWidth, requestedMa
|
|
|
210
211
|
'Write-Output (@{ ok=$true; left=$x; top=$y; width=$w; height=$h; capture_max_width=$maxWidth; capture_max_height=$maxHeight; image_width=$imageWidth; image_height=$imageHeight; image_bytes=$fileSize; image_quality=$qualityUsed; image_available=$imageAvailable; image_mime="image/jpeg" } | ConvertTo-Json -Compress)',
|
|
211
212
|
].join('\r\n');
|
|
212
213
|
}
|
|
214
|
+
function boundedSparseWait(value) {
|
|
215
|
+
const requested = Number(value);
|
|
216
|
+
if (!Number.isFinite(requested) || requested <= 0)
|
|
217
|
+
return 0;
|
|
218
|
+
return Math.min(MAX_SPARSE_WAIT_MS, Math.floor(requested));
|
|
219
|
+
}
|
|
220
|
+
function sparseMeasurementSampleBudget(waitMs) {
|
|
221
|
+
const boundedWait = Math.max(1, Math.floor(Number(waitMs) || 1));
|
|
222
|
+
// A live PowerShell process handshake does not mean its first GDI capture,
|
|
223
|
+
// script execution and IPC response are warm. Reserve completion time on
|
|
224
|
+
// every call so the lane's own wait-elapsed result beats the outer fallback.
|
|
225
|
+
const completionMarginMs = Math.min(Math.max(0, boundedWait - 1), Math.min(1500, Math.max(500, Math.floor(boundedWait * 0.3))));
|
|
226
|
+
return Math.max(1, boundedWait - completionMarginMs);
|
|
227
|
+
}
|
|
228
|
+
function sparseMeasurementScript(waitMs) {
|
|
229
|
+
const boundedWait = Math.min(MAX_SPARSE_WAIT_MS, Math.max(1, Math.floor(waitMs)));
|
|
230
|
+
return [
|
|
231
|
+
'$ErrorActionPreference = "Stop"',
|
|
232
|
+
'$bounds = [System.Windows.Forms.SystemInformation]::VirtualScreen',
|
|
233
|
+
'$x=[int]$bounds.Left; $y=[int]$bounds.Top; $w=[int]$bounds.Width; $h=[int]$bounds.Height',
|
|
234
|
+
'if ($w -le 0 -or $h -le 0) { throw "Virtual screen geometry is unavailable." }',
|
|
235
|
+
'$gridWidth=32; $gridHeight=18; $pollMs=200; $cellThreshold=24; $strongThreshold=64',
|
|
236
|
+
'$watch = [System.Diagnostics.Stopwatch]::StartNew(); $sampleCount=0; $changedCells=0; $triggered=$false; $geometryChanged=$false',
|
|
237
|
+
'$thumbnail = [NewmarkSparseCapture]::CaptureScaled($x,$y,$w,$h,$gridWidth,$gridHeight)',
|
|
238
|
+
'$baseline = [byte[]]::new($gridWidth * $gridHeight)',
|
|
239
|
+
'try {',
|
|
240
|
+
' for ($row=0; $row -lt $gridHeight; $row++) { for ($column=0; $column -lt $gridWidth; $column++) { $index=$row*$gridWidth+$column; $baseline[$index]=$thumbnail.GetLuma($column,$row) } }',
|
|
241
|
+
' $sampleCount=1',
|
|
242
|
+
` while ($watch.ElapsedMilliseconds -lt ${boundedWait}) {`,
|
|
243
|
+
` $remaining=[Math]::Max(1, ${boundedWait} - [int]$watch.ElapsedMilliseconds); Start-Sleep -Milliseconds ([Math]::Min($pollMs,$remaining))`,
|
|
244
|
+
' $nextBounds=[System.Windows.Forms.SystemInformation]::VirtualScreen',
|
|
245
|
+
' if ($nextBounds.Left -ne $x -or $nextBounds.Top -ne $y -or $nextBounds.Width -ne $w -or $nextBounds.Height -ne $h) { $geometryChanged=$true; break }',
|
|
246
|
+
' $nextThumbnail=[NewmarkSparseCapture]::CaptureScaled($x,$y,$w,$h,$gridWidth,$gridHeight); $thumbnail.Dispose(); $thumbnail=$nextThumbnail',
|
|
247
|
+
' $changedCells=0; $strongCells=0',
|
|
248
|
+
' for ($row=0; $row -lt $gridHeight; $row++) { for ($column=0; $column -lt $gridWidth; $column++) { $index=$row*$gridWidth+$column; $luma=[int]$thumbnail.GetLuma($column,$row); $delta=[Math]::Abs($luma-$baseline[$index]); if ($delta -ge $cellThreshold) { $changedCells++ }; if ($delta -ge $strongThreshold) { $strongCells++ } } }',
|
|
249
|
+
' $sampleCount++',
|
|
250
|
+
' if ($changedCells -ge 4 -or $strongCells -ge 2) { $triggered=$true; break }',
|
|
251
|
+
' }',
|
|
252
|
+
].join('\r\n') + [
|
|
253
|
+
'} finally { $watch.Stop(); $thumbnail.Dispose() }',
|
|
254
|
+
'$reason = if ($geometryChanged) { "screen_geometry_changed" } elseif ($triggered) { "coarse_change" } else { "wait_elapsed" }',
|
|
255
|
+
'Write-Output (@{ ok=$true; triggered=$triggered; geometry_changed=$geometryChanged; sample_count=$sampleCount; changed_cells=$changedCells; elapsed_ms=[int]$watch.ElapsedMilliseconds; reason=$reason } | ConvertTo-Json -Compress)',
|
|
256
|
+
].join('\r\n');
|
|
257
|
+
}
|
|
258
|
+
function sparseAbortError(signal) {
|
|
259
|
+
if (signal.reason instanceof Error)
|
|
260
|
+
return signal.reason;
|
|
261
|
+
return new Error(signal.reason ? String(signal.reason) : 'Computer Use sparse observation was cancelled.');
|
|
262
|
+
}
|
|
263
|
+
async function waitForSparseChange(waitMs, signal) {
|
|
264
|
+
if (signal?.aborted)
|
|
265
|
+
throw sparseAbortError(signal);
|
|
266
|
+
return await new Promise((resolve, reject) => {
|
|
267
|
+
let settled = false;
|
|
268
|
+
let phase = 'preparing';
|
|
269
|
+
const deadlineAt = Date.now() + waitMs;
|
|
270
|
+
let deadlineTimer;
|
|
271
|
+
const cleanup = () => {
|
|
272
|
+
if (deadlineTimer)
|
|
273
|
+
clearTimeout(deadlineTimer);
|
|
274
|
+
signal?.removeEventListener('abort', onAbort);
|
|
275
|
+
};
|
|
276
|
+
const onAbort = () => {
|
|
277
|
+
if (settled)
|
|
278
|
+
return;
|
|
279
|
+
settled = true;
|
|
280
|
+
cleanup();
|
|
281
|
+
(0, computerUsePowerShellHost_1.stopComputerUsePowerShellLane)('sparse');
|
|
282
|
+
reject(sparseAbortError(signal));
|
|
283
|
+
};
|
|
284
|
+
deadlineTimer = setTimeout(() => {
|
|
285
|
+
if (settled)
|
|
286
|
+
return;
|
|
287
|
+
settled = true;
|
|
288
|
+
cleanup();
|
|
289
|
+
// A normal wait deadline during helper startup must not kill the shared
|
|
290
|
+
// lane. Its initialization can finish in the background and serve the
|
|
291
|
+
// next observation. Once a sample has actually been submitted, however,
|
|
292
|
+
// stop a worker that failed to return before its bounded sampling window.
|
|
293
|
+
if (phase === 'sampling')
|
|
294
|
+
(0, computerUsePowerShellHost_1.stopComputerUsePowerShellLane)('sparse');
|
|
295
|
+
const error = phase === 'preparing'
|
|
296
|
+
? 'Sparse helper did not become ready before the observation deadline; its startup continues for the next observation.'
|
|
297
|
+
: 'Sparse sample did not return before the observation deadline; continuing with a fresh full observation.';
|
|
298
|
+
resolve({ ok: false, triggered: false, geometryChanged: false, sampleCount: null, changedCells: null, elapsedMs: waitMs, reason: 'wait_elapsed', error });
|
|
299
|
+
}, waitMs);
|
|
300
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
301
|
+
if (signal?.aborted) {
|
|
302
|
+
onAbort();
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
const parseResult = (result) => {
|
|
306
|
+
if (settled)
|
|
307
|
+
return;
|
|
308
|
+
settled = true;
|
|
309
|
+
cleanup();
|
|
310
|
+
if (!result.ok) {
|
|
311
|
+
resolve({ ok: false, triggered: false, geometryChanged: false, sampleCount: null, changedCells: null, elapsedMs: result.elapsedMs, reason: 'sampling_failed', error: result.output.slice(0, 500) });
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
try {
|
|
315
|
+
const parsed = JSON.parse(result.output);
|
|
316
|
+
resolve({
|
|
317
|
+
ok: parsed.ok === true,
|
|
318
|
+
triggered: parsed.triggered === true,
|
|
319
|
+
geometryChanged: parsed.geometry_changed === true,
|
|
320
|
+
sampleCount: Math.max(0, Number(parsed.sample_count) || 0),
|
|
321
|
+
changedCells: Math.max(0, Number(parsed.changed_cells) || 0),
|
|
322
|
+
elapsedMs: Math.max(0, Number(parsed.elapsed_ms) || result.elapsedMs),
|
|
323
|
+
reason: String(parsed.reason || 'sampling_failed'),
|
|
324
|
+
...(parsed.ok === true ? {} : { error: 'Sparse measurement returned an invalid result.' }),
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
catch {
|
|
328
|
+
resolve({ ok: false, triggered: false, geometryChanged: false, sampleCount: null, changedCells: null, elapsedMs: result.elapsedMs, reason: 'sampling_failed', error: 'Sparse measurement result was not valid JSON.' });
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
const prepareAndSample = async () => {
|
|
332
|
+
const preparation = await (0, computerUsePowerShellHost_1.prepareComputerUsePowerShellLane)('sparse', waitMs);
|
|
333
|
+
if (settled)
|
|
334
|
+
return;
|
|
335
|
+
if (!preparation.ready) {
|
|
336
|
+
settled = true;
|
|
337
|
+
cleanup();
|
|
338
|
+
resolve({
|
|
339
|
+
ok: false,
|
|
340
|
+
triggered: false,
|
|
341
|
+
geometryChanged: false,
|
|
342
|
+
sampleCount: null,
|
|
343
|
+
changedCells: null,
|
|
344
|
+
elapsedMs: Math.max(preparation.elapsedMs, Date.now() - (deadlineAt - waitMs)),
|
|
345
|
+
reason: 'wait_elapsed',
|
|
346
|
+
error: 'Sparse helper initialization exceeded the observation deadline; the lane remains available to finish startup.',
|
|
347
|
+
});
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
const remainingMs = Math.max(0, deadlineAt - Date.now());
|
|
351
|
+
if (remainingMs < 100) {
|
|
352
|
+
settled = true;
|
|
353
|
+
cleanup();
|
|
354
|
+
resolve({ ok: false, triggered: false, geometryChanged: false, sampleCount: null, changedCells: null, elapsedMs: waitMs, reason: 'wait_elapsed', error: 'Sparse helper became ready without enough time left to capture a bounded sample.' });
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
const sampleBudgetMs = sparseMeasurementSampleBudget(remainingMs);
|
|
358
|
+
phase = 'sampling';
|
|
359
|
+
try {
|
|
360
|
+
const result = await (0, computerUsePowerShellHost_1.runPersistentPowerShell)(sparseMeasurementScript(sampleBudgetMs), remainingMs, 'sparse');
|
|
361
|
+
parseResult(result);
|
|
362
|
+
}
|
|
363
|
+
catch (error) {
|
|
364
|
+
if (settled)
|
|
365
|
+
return;
|
|
366
|
+
settled = true;
|
|
367
|
+
cleanup();
|
|
368
|
+
resolve({ ok: false, triggered: false, geometryChanged: false, sampleCount: null, changedCells: null, elapsedMs: Date.now() - (deadlineAt - waitMs), reason: 'sampling_failed', error: error instanceof Error ? error.message.slice(0, 500) : String(error).slice(0, 500) });
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
void prepareAndSample().catch(error => {
|
|
372
|
+
if (settled)
|
|
373
|
+
return;
|
|
374
|
+
settled = true;
|
|
375
|
+
cleanup();
|
|
376
|
+
resolve({ ok: false, triggered: false, geometryChanged: false, sampleCount: null, changedCells: null, elapsedMs: Date.now() - (deadlineAt - waitMs), reason: 'sampling_failed', error: error instanceof Error ? error.message.slice(0, 500) : String(error).slice(0, 500) });
|
|
377
|
+
});
|
|
378
|
+
});
|
|
379
|
+
}
|
|
213
380
|
function gradientPalette(_input) {
|
|
214
381
|
return ['#000000', '#ffffff', '#000000', '#ffffff'];
|
|
215
382
|
}
|
|
@@ -438,11 +605,15 @@ function sceneGeneration(apps, elements) {
|
|
|
438
605
|
async function observeUiAutomation(maxChars, rootHandle, timeoutMs = 30000, lane = 'uia') {
|
|
439
606
|
const limit = Math.min(Math.max(Math.floor(maxChars || 30000), 1000), 200000);
|
|
440
607
|
const handleHex = String(rootHandle || '').trim().replace(/^0x/i, '').replace(/[^0-9a-f]/gi, '');
|
|
608
|
+
if (!/[1-9a-f]/i.test(handleHex)) {
|
|
609
|
+
return { elements: [], visited: 0, error: 'Window-scoped UI Automation requires a non-zero native window handle.', elapsedMs: 0 };
|
|
610
|
+
}
|
|
611
|
+
const hostProcessId = Math.max(1, Math.floor(process.pid));
|
|
441
612
|
const script = [
|
|
442
|
-
handleHex
|
|
443
|
-
? `$nativeHandle = [System.IntPtr]::new([Convert]::ToInt64(${psQuote(handleHex)}, 16)); $root = [System.Windows.Automation.AutomationElement]::FromHandle($nativeHandle)`
|
|
444
|
-
: '$root = [System.Windows.Automation.AutomationElement]::RootElement',
|
|
613
|
+
`$nativeHandle = [System.IntPtr]::new([Convert]::ToInt64(${psQuote(handleHex)}, 16)); $root = [System.Windows.Automation.AutomationElement]::FromHandle($nativeHandle)`,
|
|
445
614
|
'if ($null -eq $root) { throw "UI Automation root is unavailable." }',
|
|
615
|
+
'$rootProcessId = 0; try { $rootProcessId = [int]$root.Current.ProcessId } catch {}',
|
|
616
|
+
`if ($rootProcessId -eq ${hostProcessId}) { throw "UI Automation of the Newmark host window is skipped to avoid Electron self-accessibility hangs." }`,
|
|
446
617
|
'$cache = New-Object System.Windows.Automation.CacheRequest',
|
|
447
618
|
'$cache.TreeScope = [System.Windows.Automation.TreeScope]::Element',
|
|
448
619
|
'$cache.TreeFilter = [System.Windows.Automation.Automation]::ControlViewCondition',
|
|
@@ -496,6 +667,9 @@ async function observeUiAutomation(maxChars, rootHandle, timeoutMs = 30000, lane
|
|
|
496
667
|
return { elements: parseJsonArray(result.output), visited: 0, error: 'UI Automation returned invalid JSON.', elapsedMs: result.elapsedMs };
|
|
497
668
|
}
|
|
498
669
|
}
|
|
670
|
+
function skippedUiAutomation(error) {
|
|
671
|
+
return { elements: [], visited: 0, ...(error ? { error } : {}), elapsedMs: 0 };
|
|
672
|
+
}
|
|
499
673
|
async function observeAppWindows(maxChars, timeoutMs = 30000, lane = 'windows') {
|
|
500
674
|
const limit = Math.min(Math.max(Math.floor(maxChars || 30000), 1000), 200000);
|
|
501
675
|
const script = [
|
|
@@ -597,7 +771,162 @@ async function selectAppWindow(target, handle) {
|
|
|
597
771
|
return { apps, error: `No visible application window matched: ${target || handle}.`, elapsedMs: observed.elapsedMs };
|
|
598
772
|
return { app, apps, elapsedMs: observed.elapsedMs };
|
|
599
773
|
}
|
|
600
|
-
|
|
774
|
+
const MAX_WAIT_FOR_TIMEOUT_MS = 30_000;
|
|
775
|
+
const DEFAULT_WAIT_FOR_TIMEOUT_MS = 5_000;
|
|
776
|
+
const WAIT_FOR_POLL_INTERVAL_MS = 250;
|
|
777
|
+
function boundedWaitForTimeout(value) {
|
|
778
|
+
const requested = Number(value);
|
|
779
|
+
if (!Number.isFinite(requested) || requested <= 0)
|
|
780
|
+
return DEFAULT_WAIT_FOR_TIMEOUT_MS;
|
|
781
|
+
return Math.min(MAX_WAIT_FOR_TIMEOUT_MS, Math.max(WAIT_FOR_POLL_INTERVAL_MS, Math.floor(requested)));
|
|
782
|
+
}
|
|
783
|
+
async function waitForUi(options, ownerId) {
|
|
784
|
+
const startedAt = Date.now();
|
|
785
|
+
const timeoutMs = boundedWaitForTimeout(options.timeoutMs);
|
|
786
|
+
const deadline = startedAt + timeoutMs;
|
|
787
|
+
const workspacePath = options.workspacePath;
|
|
788
|
+
const cache = observations.get(observationKey(workspacePath, ownerId));
|
|
789
|
+
const requestedText = String(options.text || '').trim();
|
|
790
|
+
const normalizedQuery = normalizeText(requestedText);
|
|
791
|
+
const targetId = String(options.targetId || '').trim();
|
|
792
|
+
const appTarget = String(options.appTarget || '').trim();
|
|
793
|
+
const requestedHandle = String(options.windowHandle || '').trim();
|
|
794
|
+
const cachedTarget = targetId ? cache?.objects.find(object => object.target_id === targetId) : undefined;
|
|
795
|
+
let app;
|
|
796
|
+
let lastWindowError;
|
|
797
|
+
let attempts = 0;
|
|
798
|
+
let nextWindowPollAt = 0;
|
|
799
|
+
if (!normalizedQuery && !targetId && !appTarget && !requestedHandle) {
|
|
800
|
+
return { ok: false, action: 'wait_for', error: 'Provide text, target_id, app_target, or window_handle to wait for.' };
|
|
801
|
+
}
|
|
802
|
+
if (targetId && !cachedTarget) {
|
|
803
|
+
return { ok: false, action: 'wait_for', error: `target_id not found in latest observation: ${targetId}. Call computer_use observe first.` };
|
|
804
|
+
}
|
|
805
|
+
const directHandle = requestedHandle || (!appTarget ? String(cache?.windowHandle || '') : '');
|
|
806
|
+
if (directHandle) {
|
|
807
|
+
const direct = await observeAppWindowByHandle(directHandle);
|
|
808
|
+
attempts += 1;
|
|
809
|
+
if (!direct.app) {
|
|
810
|
+
return { ok: false, action: 'wait_for', status: 'window_unavailable', error: direct.error || 'The selected window is no longer available.', elapsed_ms: Date.now() - startedAt, attempts };
|
|
811
|
+
}
|
|
812
|
+
app = direct.app;
|
|
813
|
+
}
|
|
814
|
+
if (!app && !appTarget) {
|
|
815
|
+
return { ok: false, action: 'wait_for', error: 'Call computer_use observe/app_observe first, or provide app_target/window_handle.' };
|
|
816
|
+
}
|
|
817
|
+
if (targetId && cache?.windowHandle && app && cache.windowHandle.toLowerCase() !== app.handle.toLowerCase()) {
|
|
818
|
+
return { ok: false, action: 'wait_for', error: `target_id=${targetId} belongs to a different window than ${app.handle}. Observe that window before waiting on the target.` };
|
|
819
|
+
}
|
|
820
|
+
while (Date.now() <= deadline) {
|
|
821
|
+
if (options.signal?.aborted) {
|
|
822
|
+
return { ok: false, action: 'wait_for', status: 'cancelled', error: 'wait_for was cancelled.', elapsed_ms: Date.now() - startedAt, attempts };
|
|
823
|
+
}
|
|
824
|
+
if (!app && appTarget) {
|
|
825
|
+
if (Date.now() >= nextWindowPollAt) {
|
|
826
|
+
const observed = await observeAppWindows(30000, 750, 'windows_advisory');
|
|
827
|
+
attempts += 1;
|
|
828
|
+
lastWindowError = observed.error;
|
|
829
|
+
app = observed.apps.find(candidate => appMatches(candidate, appTarget));
|
|
830
|
+
nextWindowPollAt = Date.now() + 1000;
|
|
831
|
+
}
|
|
832
|
+
if (!app) {
|
|
833
|
+
const remaining = deadline - Date.now();
|
|
834
|
+
if (remaining <= 0)
|
|
835
|
+
break;
|
|
836
|
+
await new Promise(resolve => setTimeout(resolve, Math.min(Math.max(1, nextWindowPollAt - Date.now()), remaining)));
|
|
837
|
+
continue;
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
if (targetId && cache?.windowHandle && app && cache.windowHandle.toLowerCase() !== app.handle.toLowerCase()) {
|
|
841
|
+
return { ok: false, action: 'wait_for', error: `target_id=${targetId} belongs to a different window than ${app.handle}. Observe that window before waiting on the target.`, elapsed_ms: Date.now() - startedAt, attempts };
|
|
842
|
+
}
|
|
843
|
+
if (app && !normalizedQuery && !targetId) {
|
|
844
|
+
return {
|
|
845
|
+
ok: true,
|
|
846
|
+
action: 'wait_for',
|
|
847
|
+
status: 'matched',
|
|
848
|
+
found: true,
|
|
849
|
+
condition: { app_target: appTarget || undefined, window_handle: app.handle },
|
|
850
|
+
app,
|
|
851
|
+
elapsed_ms: Date.now() - startedAt,
|
|
852
|
+
attempts,
|
|
853
|
+
};
|
|
854
|
+
}
|
|
855
|
+
if (app) {
|
|
856
|
+
const ui = await observeUiAutomation(Number(options.maxChars || 30000), app.handle, 750, 'uia_advisory');
|
|
857
|
+
attempts += 1;
|
|
858
|
+
if (ui.error) {
|
|
859
|
+
return { ok: false, action: 'wait_for', status: 'uia_unavailable', error: ui.error, app, elapsed_ms: Date.now() - startedAt, attempts };
|
|
860
|
+
}
|
|
861
|
+
const objects = semanticObjects(ui.elements, app.bbox.width, app.bbox.height, workspacePath, ownerId);
|
|
862
|
+
const match = objects.find(object => {
|
|
863
|
+
if (targetId && object.target_id !== targetId)
|
|
864
|
+
return false;
|
|
865
|
+
if (!normalizedQuery)
|
|
866
|
+
return true;
|
|
867
|
+
return normalizeText(object.name).includes(normalizedQuery) || normalizeText(object.automation_id).includes(normalizedQuery);
|
|
868
|
+
});
|
|
869
|
+
if (match) {
|
|
870
|
+
const generation = sceneGeneration([app], ui.elements);
|
|
871
|
+
observations.set(observationKey(workspacePath, ownerId), {
|
|
872
|
+
workspacePath,
|
|
873
|
+
objects,
|
|
874
|
+
windowHandle: app.handle,
|
|
875
|
+
width: Math.max(1, app.bbox.width),
|
|
876
|
+
height: Math.max(1, app.bbox.height),
|
|
877
|
+
at: new Date().toISOString(),
|
|
878
|
+
sceneGeneration: generation,
|
|
879
|
+
});
|
|
880
|
+
return {
|
|
881
|
+
ok: true,
|
|
882
|
+
action: 'wait_for',
|
|
883
|
+
status: 'matched',
|
|
884
|
+
found: true,
|
|
885
|
+
condition: {
|
|
886
|
+
...(requestedText ? { text: requestedText } : {}),
|
|
887
|
+
...(targetId ? { target_id: targetId } : {}),
|
|
888
|
+
...(appTarget ? { app_target: appTarget } : {}),
|
|
889
|
+
},
|
|
890
|
+
app,
|
|
891
|
+
scene_generation: generation,
|
|
892
|
+
element: {
|
|
893
|
+
target_id: match.target_id,
|
|
894
|
+
label: match.label,
|
|
895
|
+
role: match.role,
|
|
896
|
+
control_type: match.control_type,
|
|
897
|
+
automation_id: match.automation_id,
|
|
898
|
+
bbox: match.bbox,
|
|
899
|
+
center: match.center,
|
|
900
|
+
},
|
|
901
|
+
elapsed_ms: Date.now() - startedAt,
|
|
902
|
+
attempts,
|
|
903
|
+
};
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
const remaining = deadline - Date.now();
|
|
907
|
+
if (remaining <= 0)
|
|
908
|
+
break;
|
|
909
|
+
await new Promise(resolve => setTimeout(resolve, Math.min(WAIT_FOR_POLL_INTERVAL_MS, remaining)));
|
|
910
|
+
}
|
|
911
|
+
return {
|
|
912
|
+
ok: true,
|
|
913
|
+
action: 'wait_for',
|
|
914
|
+
status: 'timed_out',
|
|
915
|
+
found: false,
|
|
916
|
+
condition: {
|
|
917
|
+
...(requestedText ? { text: requestedText } : {}),
|
|
918
|
+
...(targetId ? { target_id: targetId } : {}),
|
|
919
|
+
...(appTarget ? { app_target: appTarget } : {}),
|
|
920
|
+
...(requestedHandle ? { window_handle: requestedHandle } : {}),
|
|
921
|
+
},
|
|
922
|
+
...(app ? { app } : {}),
|
|
923
|
+
...(lastWindowError ? { warning: lastWindowError } : {}),
|
|
924
|
+
timeout_ms: timeoutMs,
|
|
925
|
+
elapsed_ms: Date.now() - startedAt,
|
|
926
|
+
attempts,
|
|
927
|
+
};
|
|
928
|
+
}
|
|
929
|
+
async function cropScreenshot(workspacePath, ownerId, allowEphemeralVisionImage, app, includeRawUi = false, captureMaxWidth, captureMaxHeight, includeUiTree = true) {
|
|
601
930
|
const totalStarted = Date.now();
|
|
602
931
|
const outPath = ephemeralScreenshotPath('app');
|
|
603
932
|
let retainedForVision = false;
|
|
@@ -608,7 +937,9 @@ async function cropScreenshot(workspacePath, ownerId, allowEphemeralVisionImage,
|
|
|
608
937
|
], captureMaxWidth, captureMaxHeight);
|
|
609
938
|
const [result, ui] = await Promise.all([
|
|
610
939
|
runPowerShell(script, 30000),
|
|
611
|
-
|
|
940
|
+
includeUiTree
|
|
941
|
+
? observeUiAutomation(30000, app.handle, 750, 'uia_advisory')
|
|
942
|
+
: Promise.resolve(skippedUiAutomation()),
|
|
612
943
|
]);
|
|
613
944
|
if (!result.ok)
|
|
614
945
|
return captureFailure('app_observe', app);
|
|
@@ -631,7 +962,7 @@ async function cropScreenshot(workspacePath, ownerId, allowEphemeralVisionImage,
|
|
|
631
962
|
}
|
|
632
963
|
const cacheKey = observationKey(workspacePath, ownerId);
|
|
633
964
|
const generation = sceneGeneration([app], elements);
|
|
634
|
-
observations.set(cacheKey, { workspacePath, objects, width: Number(parsed.width || b.width || 1), height: Number(parsed.height || b.height || 1), at: new Date().toISOString(), sceneGeneration: generation });
|
|
965
|
+
observations.set(cacheKey, { workspacePath, objects, windowHandle: app.handle, width: Number(parsed.width || b.width || 1), height: Number(parsed.height || b.height || 1), at: new Date().toISOString(), sceneGeneration: generation });
|
|
635
966
|
const payload = {
|
|
636
967
|
ok: true,
|
|
637
968
|
action: 'app_observe',
|
|
@@ -640,8 +971,10 @@ async function cropScreenshot(workspacePath, ownerId, allowEphemeralVisionImage,
|
|
|
640
971
|
screenshot_retention: allowEphemeralVisionImage ? 'ephemeral-delete-after-vision-input' : 'ephemeral-deleted-before-tool-return',
|
|
641
972
|
coordinate_system: 'virtual-screen-pixels',
|
|
642
973
|
perception: {
|
|
643
|
-
mode: 'native-application-screenshot-plus-windows-ui-automation',
|
|
974
|
+
mode: includeUiTree ? 'native-application-screenshot-plus-windows-ui-automation' : 'native-application-screenshot-only',
|
|
644
975
|
application_scope: 'single-visible-window',
|
|
976
|
+
ui_tree_status: includeUiTree ? (ui.error ? 'unavailable' : 'captured') : 'skipped',
|
|
977
|
+
ui_tree_skipped: !includeUiTree,
|
|
645
978
|
element_count: elements.length,
|
|
646
979
|
visited_count: ui.visited,
|
|
647
980
|
scene_generation: generation,
|
|
@@ -652,6 +985,7 @@ async function cropScreenshot(workspacePath, ownerId, allowEphemeralVisionImage,
|
|
|
652
985
|
telemetry: {
|
|
653
986
|
capture_ms: result.elapsedMs,
|
|
654
987
|
uia_ms: ui.elapsedMs,
|
|
988
|
+
ui_tree_skipped: !includeUiTree,
|
|
655
989
|
total_ms: Date.now() - totalStarted,
|
|
656
990
|
element_count: elements.length,
|
|
657
991
|
visited_count: ui.visited,
|
|
@@ -901,8 +1235,28 @@ function resolveTarget(targetId, workspacePath, ownerId) {
|
|
|
901
1235
|
return { x: 0, y: 0, error: `target_id not found in latest observation: ${id}.` };
|
|
902
1236
|
return { x: target.center.x, y: target.center.y, target };
|
|
903
1237
|
}
|
|
904
|
-
async function screenshot(workspacePath, ownerId, allowEphemeralVisionImage, includeRawUi = false, captureMaxWidth, captureMaxHeight) {
|
|
1238
|
+
async function screenshot(workspacePath, ownerId, allowEphemeralVisionImage, includeRawUi = false, captureMaxWidth, captureMaxHeight, sparseWaitMs, signal, includeUiTree = true) {
|
|
905
1239
|
const totalStarted = Date.now();
|
|
1240
|
+
const sparseDurationMs = boundedSparseWait(sparseWaitMs);
|
|
1241
|
+
const sparseStarted = Date.now();
|
|
1242
|
+
const sparse = sparseDurationMs > 0 ? await waitForSparseChange(sparseDurationMs, signal) : undefined;
|
|
1243
|
+
const sparseWallMs = sparse ? Date.now() - sparseStarted : 0;
|
|
1244
|
+
if (signal?.aborted)
|
|
1245
|
+
throw sparseAbortError(signal);
|
|
1246
|
+
const sparseDetails = sparse ? {
|
|
1247
|
+
method: 'coarse-grid-luminance-change-wakeup',
|
|
1248
|
+
grid_width: 32,
|
|
1249
|
+
grid_height: 18,
|
|
1250
|
+
sample_count: sparse.sampleCount,
|
|
1251
|
+
changed_cells: sparse.changedCells,
|
|
1252
|
+
triggered: sparse.triggered,
|
|
1253
|
+
reason: sparse.reason,
|
|
1254
|
+
elapsed_ms: sparse.elapsedMs,
|
|
1255
|
+
wall_elapsed_ms: sparseWallMs,
|
|
1256
|
+
fresh_full_observation_follows: true,
|
|
1257
|
+
interpretation: 'Wake signal only. A timeout or no detected change is not evidence that the screen stayed unchanged; small, brief, or color-only changes can be missed.',
|
|
1258
|
+
...(sparse.error ? { warning: sparse.error } : {}),
|
|
1259
|
+
} : undefined;
|
|
906
1260
|
const outPath = ephemeralScreenshotPath('observe');
|
|
907
1261
|
let retainedForVision = false;
|
|
908
1262
|
try {
|
|
@@ -913,23 +1267,29 @@ async function screenshot(workspacePath, ownerId, allowEphemeralVisionImage, inc
|
|
|
913
1267
|
const foreground = await foregroundWindowHandle();
|
|
914
1268
|
const [result, ui, apps] = await Promise.all([
|
|
915
1269
|
runPowerShell(script, 30000),
|
|
916
|
-
|
|
917
|
-
|
|
1270
|
+
includeUiTree && foreground.handle
|
|
1271
|
+
? observeUiAutomation(30000, foreground.handle, 750, 'uia_advisory')
|
|
1272
|
+
: Promise.resolve(skippedUiAutomation(includeUiTree ? 'Foreground window handle is unavailable; UI Automation tree capture was skipped.' : undefined)),
|
|
1273
|
+
includeUiTree
|
|
1274
|
+
? observeAppWindows(30000, 750, 'windows_advisory')
|
|
1275
|
+
: Promise.resolve({ apps: [], error: undefined, elapsedMs: 0 }),
|
|
918
1276
|
]);
|
|
1277
|
+
if (signal?.aborted)
|
|
1278
|
+
throw sparseAbortError(signal);
|
|
919
1279
|
if (!result.ok)
|
|
920
|
-
return captureFailure('observe');
|
|
1280
|
+
return { ...captureFailure('observe'), ...(sparseDetails ? { sparse_measurement: sparseDetails } : {}) };
|
|
921
1281
|
let parsed = {};
|
|
922
1282
|
try {
|
|
923
1283
|
parsed = JSON.parse(result.output);
|
|
924
1284
|
}
|
|
925
1285
|
catch {
|
|
926
|
-
return captureFailure('observe');
|
|
1286
|
+
return { ...captureFailure('observe'), ...(sparseDetails ? { sparse_measurement: sparseDetails } : {}) };
|
|
927
1287
|
}
|
|
928
1288
|
const screenWidth = Number(parsed.width || 1);
|
|
929
1289
|
const screenHeight = Number(parsed.height || 1);
|
|
930
1290
|
const objects = semanticObjects(ui.elements, screenWidth, screenHeight, workspacePath, ownerId);
|
|
931
1291
|
const generation = sceneGeneration(apps.apps, ui.elements);
|
|
932
|
-
observations.set(observationKey(workspacePath, ownerId), { workspacePath, objects, width: screenWidth, height: screenHeight, at: new Date().toISOString(), sceneGeneration: generation });
|
|
1292
|
+
observations.set(observationKey(workspacePath, ownerId), { workspacePath, objects, windowHandle: foreground.handle || undefined, width: screenWidth, height: screenHeight, at: new Date().toISOString(), sceneGeneration: generation });
|
|
933
1293
|
const payload = {
|
|
934
1294
|
ok: true,
|
|
935
1295
|
action: 'observe',
|
|
@@ -937,28 +1297,47 @@ async function screenshot(workspacePath, ownerId, allowEphemeralVisionImage, inc
|
|
|
937
1297
|
screenshot_retention: allowEphemeralVisionImage ? 'ephemeral-delete-after-vision-input' : 'ephemeral-deleted-before-tool-return',
|
|
938
1298
|
coordinate_system: 'virtual-screen-pixels',
|
|
939
1299
|
perception: {
|
|
940
|
-
mode: 'native-screenshot-plus-windows-ui-automation',
|
|
1300
|
+
mode: includeUiTree ? 'native-screenshot-plus-windows-ui-automation' : 'native-screenshot-only',
|
|
1301
|
+
ui_tree_status: includeUiTree ? (ui.error ? 'unavailable' : 'captured') : 'skipped',
|
|
1302
|
+
ui_tree_skipped: !includeUiTree,
|
|
941
1303
|
vision_assist: {
|
|
942
|
-
when_model_supports_vision:
|
|
943
|
-
|
|
1304
|
+
when_model_supports_vision: includeUiTree
|
|
1305
|
+
? 'The Agent sends this screenshot as image input together with the UI Automation element tree, so visual recognition and control bounding boxes can be used in the same decision step.'
|
|
1306
|
+
: 'The Agent receives this screenshot as image input without UI Automation traversal or semantic target IDs.',
|
|
1307
|
+
fallback_without_vision: includeUiTree
|
|
1308
|
+
? 'Use the UI Automation element tree, bbox, center coordinates, and semantic target IDs only; no screenshot file path is retained or exposed.'
|
|
1309
|
+
: 'This result has no semantic target IDs; request include_ui_tree=true for a UI Automation element tree.',
|
|
944
1310
|
},
|
|
945
1311
|
element_count: ui.elements.length,
|
|
946
1312
|
visited_count: ui.visited,
|
|
947
1313
|
scene_generation: generation,
|
|
948
1314
|
scene_summary: buildSceneSummary(objects, screenWidth, screenHeight),
|
|
949
1315
|
objects: compactSemanticObjects(objects),
|
|
950
|
-
|
|
1316
|
+
...(sparseDetails ? { sparse_measurement: sparseDetails } : {}),
|
|
1317
|
+
object_usage: includeUiTree
|
|
1318
|
+
? 'Prefer target_id from scene_summary.high_priority_objects or objects for click/move/scroll when available; it resolves to the latest observed center coordinate and keeps actions tied to a semantic UI object.'
|
|
1319
|
+
: 'This screenshot-only observation has no semantic target IDs. Use visual coordinates or request another observe with include_ui_tree=true before using target_id.',
|
|
951
1320
|
warning: foreground.error || ui.error || apps.error || undefined,
|
|
952
|
-
note:
|
|
1321
|
+
note: includeUiTree
|
|
1322
|
+
? 'Native screenshot plus a bounded, foreground-window-scoped Windows UI Automation tree. No third-party server or code is loaded.'
|
|
1323
|
+
: 'Fast native screenshot path; UI Automation traversal was intentionally skipped. No third-party server or code is loaded.',
|
|
953
1324
|
},
|
|
954
1325
|
telemetry: {
|
|
955
1326
|
capture_ms: result.elapsedMs,
|
|
956
1327
|
uia_ms: ui.elapsedMs,
|
|
1328
|
+
ui_tree_skipped: !includeUiTree,
|
|
957
1329
|
app_list_ms: apps.elapsedMs,
|
|
958
1330
|
foreground_ms: foreground.elapsedMs,
|
|
959
1331
|
total_ms: Date.now() - totalStarted,
|
|
960
1332
|
element_count: ui.elements.length,
|
|
961
1333
|
visited_count: ui.visited,
|
|
1334
|
+
...(sparse ? {
|
|
1335
|
+
sparse_sampling_ms: sparse.elapsedMs,
|
|
1336
|
+
sparse_wall_ms: sparseWallMs,
|
|
1337
|
+
sparse_configured_wait_ms: sparseDurationMs,
|
|
1338
|
+
sparse_sample_count: sparse.sampleCount,
|
|
1339
|
+
sparse_triggered: sparse.triggered,
|
|
1340
|
+
} : {}),
|
|
962
1341
|
},
|
|
963
1342
|
...parsed,
|
|
964
1343
|
};
|
|
@@ -1093,7 +1472,9 @@ async function foregroundSceneGeneration() {
|
|
|
1093
1472
|
const handle = handleResult.handle;
|
|
1094
1473
|
const [apps, ui] = await Promise.all([
|
|
1095
1474
|
observeAppWindows(30000),
|
|
1096
|
-
|
|
1475
|
+
handle
|
|
1476
|
+
? observeUiAutomation(30000, handle)
|
|
1477
|
+
: Promise.resolve(skippedUiAutomation('Foreground window handle is unavailable; UI Automation tree capture was skipped.')),
|
|
1097
1478
|
]);
|
|
1098
1479
|
return {
|
|
1099
1480
|
generation: sceneGeneration(apps.apps, ui.elements),
|
|
@@ -1207,6 +1588,7 @@ function stringifyComputerUseResult(result) {
|
|
|
1207
1588
|
exports.computerUseInternals = {
|
|
1208
1589
|
cleanupStaleScreenshots,
|
|
1209
1590
|
ephemeralScreenshotPath,
|
|
1591
|
+
sparseMeasurementSampleBudget,
|
|
1210
1592
|
stringifyComputerUseResult,
|
|
1211
1593
|
};
|
|
1212
1594
|
async function runComputerUse(options) {
|
|
@@ -1230,7 +1612,7 @@ async function runComputerUse(options) {
|
|
|
1230
1612
|
result = { ok: true, action: 'takeover_stop', takeover: false };
|
|
1231
1613
|
}
|
|
1232
1614
|
else if (action === 'observe') {
|
|
1233
|
-
result = await screenshot(options.workspacePath, ownerId, !!options.allowEphemeralVisionImage, !!options.includeRawUi, options.captureMaxWidth, options.captureMaxHeight);
|
|
1615
|
+
result = await screenshot(options.workspacePath, ownerId, !!options.allowEphemeralVisionImage, !!options.includeRawUi, options.captureMaxWidth, options.captureMaxHeight, options.sparseWaitMs, options.signal, options.includeUiTree !== false);
|
|
1234
1616
|
}
|
|
1235
1617
|
else if (action === 'app_list') {
|
|
1236
1618
|
const first = await observeAppWindows(Number(options.maxChars || 60000));
|
|
@@ -1247,7 +1629,7 @@ async function runComputerUse(options) {
|
|
|
1247
1629
|
else if (action === 'app_observe') {
|
|
1248
1630
|
const selected = await selectAppWindow(options.appTarget, options.windowHandle);
|
|
1249
1631
|
result = selected.app
|
|
1250
|
-
? await cropScreenshot(options.workspacePath, ownerId, !!options.allowEphemeralVisionImage, selected.app, !!options.includeRawUi, options.captureMaxWidth, options.captureMaxHeight)
|
|
1632
|
+
? await cropScreenshot(options.workspacePath, ownerId, !!options.allowEphemeralVisionImage, selected.app, !!options.includeRawUi, options.captureMaxWidth, options.captureMaxHeight, options.includeUiTree !== false)
|
|
1251
1633
|
: { ok: false, action, error: selected.error, applications: selected.apps.slice(0, 20) };
|
|
1252
1634
|
}
|
|
1253
1635
|
else if (action === 'app_activate') {
|
|
@@ -1257,6 +1639,9 @@ async function runComputerUse(options) {
|
|
|
1257
1639
|
else if (action === 'wait') {
|
|
1258
1640
|
result = await wait(Number(options.durationMs || 1000));
|
|
1259
1641
|
}
|
|
1642
|
+
else if (action === 'wait_for') {
|
|
1643
|
+
result = await waitForUi(options, ownerId);
|
|
1644
|
+
}
|
|
1260
1645
|
else if (action === 'sequence') {
|
|
1261
1646
|
result = await executeSequence(options, ownerId);
|
|
1262
1647
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
type HelperLane = 'action' | 'uia' | 'windows' | 'uia_advisory' | 'windows_advisory';
|
|
1
|
+
type HelperLane = 'action' | 'uia' | 'windows' | 'uia_advisory' | 'windows_advisory' | 'sparse';
|
|
2
2
|
export interface PowerShellResult {
|
|
3
3
|
ok: boolean;
|
|
4
4
|
output: string;
|
|
@@ -6,6 +6,11 @@ export interface PowerShellResult {
|
|
|
6
6
|
}
|
|
7
7
|
export declare function runPersistentPowerShell(script: string, timeoutMs?: number, lane?: HelperLane): Promise<PowerShellResult>;
|
|
8
8
|
export declare function computerUsePowerShellLaneReady(lane: HelperLane): boolean;
|
|
9
|
+
export declare function prepareComputerUsePowerShellLane(lane: HelperLane, timeoutMs: number): Promise<{
|
|
10
|
+
ready: boolean;
|
|
11
|
+
elapsedMs: number;
|
|
12
|
+
}>;
|
|
13
|
+
export declare function stopComputerUsePowerShellLane(lane: HelperLane): void;
|
|
9
14
|
export declare function stopComputerUsePowerShellHost(): void;
|
|
10
15
|
export {};
|
|
11
16
|
//# sourceMappingURL=computerUsePowerShellHost.d.ts.map
|