ispyx 1.1.0 → 1.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.
@@ -68,7 +68,8 @@ try {
68
68
  # Already loaded by LogonUI from a previous install: keep it if it is byte-identical.
69
69
  if (-not (Test-Path $installedDll) -or (Get-FileHash $installedDll).Hash -ne (Get-FileHash $DllPath).Hash) { throw }
70
70
  }
71
- regsvr32.exe /s $installedDll 2>$null
71
+ # regsvr32 is a GUI-subsystem exe: a bare call returns before it finishes, so the read-back below raced it.
72
+ Start-Process -FilePath regsvr32.exe -ArgumentList '/s', "`"$installedDll`"" -Wait -WindowStyle Hidden
72
73
  $actual = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Classes\CLSID\{1aa7e1e6-21de-4ad5-ae6e-454401b4b427}\InprocServer32' -Name '(default)' -ErrorAction SilentlyContinue).'(default)'
73
74
  if ($actual -ne $installedDll) {
74
75
  throw "Registration did not take effect (registry has '$actual', expected '$installedDll')."
@@ -8,7 +8,7 @@ Set-StrictMode -Version 2
8
8
  $ErrorActionPreference = 'Continue' # best effort: still clean up what we can if one step fails
9
9
 
10
10
  $root = 'C:\ProgramData\ispyx'
11
- regsvr32.exe /u /s (Join-Path $root 'ispyx_unlock.dll') 2>$null
11
+ Start-Process -FilePath regsvr32.exe -ArgumentList '/u', '/s', "`"$(Join-Path $root 'ispyx_unlock.dll')`"" -Wait -WindowStyle Hidden
12
12
  Remove-Item -Path (Join-Path $root 'unlock.secret') -Force -ErrorAction SilentlyContinue
13
13
  Remove-Item -Path (Join-Path $root 'unlock.signal') -Force -ErrorAction SilentlyContinue
14
14
  # May be held open by a running LogonUI until the next lock cycle; harmless once unregistered.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ispyx",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "Local desktop-control MCP server: lets an AI use your keyboard, mouse and screen (windows, screenshots, clicks, typing, clipboard). stdio only, Windows and macOS.",
5
5
  "type": "module",
6
6
  "main": "src/server.js",
@@ -107,13 +107,19 @@ export async function runUpdate() {
107
107
  // quietly: the `ispyx mcp` forwarders stay connected and reach the new resident on their next call
108
108
  try { await callOwner(pipe, '__restart', {}); } catch { /* gone before answering */ }
109
109
  for (let i = 0; i < 40 && await residentRunning(pipe); i++) await sleep(150);
110
+ // the pipe frees before the process has finished exiting; it still holds koffi.node (EBUSY) until then
111
+ await sleep(2000);
110
112
  }
111
113
  step('Installing the latest ispyx (npm install -g ispyx@latest)');
112
- const code = await new Promise((resolve) => {
113
- const c = spawn('npm', ['install', '-g', 'ispyx@latest'], { stdio: 'inherit', shell: true });
114
- c.on('error', () => resolve(1));
115
- c.on('exit', (n) => resolve(n ?? 1));
116
- });
114
+ let code = 1;
115
+ for (let attempt = 0; attempt < 3 && code !== 0; attempt++) {
116
+ if (attempt) { step('Retrying (a file was still in use)'); await sleep(2500); }
117
+ code = await new Promise((resolve) => {
118
+ const c = spawn('npm', ['install', '-g', 'ispyx@latest'], { stdio: 'inherit', shell: true });
119
+ c.on('error', () => resolve(1));
120
+ c.on('exit', (n) => resolve(n ?? 1));
121
+ });
122
+ }
117
123
  if (code !== 0) process.stderr.write('ispyx: the update failed (see the npm output above).\n');
118
124
  // Start the new copy: npm replaced the files in place, so a fresh process loads them.
119
125
  if (wasRunning) { step('Starting ispyx'); spawnResident(); }
@@ -435,7 +435,9 @@ $("unlockOn").addEventListener("change",function(){
435
435
  var done=function(){busy.unlockOn=false;poll()};
436
436
  if(want){
437
437
  box.checked=false;
438
- ask("Let the AI unlock this PC",[{id:"password",label:"Windows password"}],"Turn on",function(v){return act("setUnlock",{on:true,password:v.password})});
438
+ var fields=[{id:"password",label:"Windows password"}];
439
+ if(last&&last.passwordSet)fields.push({id:"current",label:"Ispyx password"});
440
+ ask("Let the AI unlock this PC",fields,"Turn on",function(v){return act("setUnlock",{on:true,password:v.password,current:v.current})});
439
441
  done();return;
440
442
  }
441
443
  if(last&&last.passwordSet){