dsh-cliworker-now 0.7.6 → 0.7.7
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.en.md +29 -9
- package/README.md +31 -9
- package/lib/account-models.mjs +16 -13
- package/lib/client.js +658 -61
- package/lib/client.js.map +1 -1
- package/lib/grok-catalog.mjs +2 -2
- package/lib/hermes-native-entry.py +48 -13
- package/lib/hermes-nous-refresh.py +331 -0
- package/lib/index.js +3724 -1589
- package/lib/index.js.map +1 -1
- package/lib/native-launch.mjs +62 -7
- package/lib/native-spawn.mjs +32 -0
- package/lib/pi-installation.mjs +27 -3
- package/lib/pi-native-catalog.mjs +2 -2
- package/lib/pi-omp-bridge.mjs +2 -2
- package/lib/private-launch.mjs +6 -2
- package/lib/terminal-bridge.mjs +2 -2
- package/lib/typert.host.js +83 -11
- package/lib/typert.remote-client.d.ts +2 -0
- package/lib/typert.remote-client.d.ts.map +1 -1
- package/lib/typert.remote-client.js +77 -11
- package/lib/types/client/account-query-queue.d.ts +16 -0
- package/lib/types/client/account-query-queue.js +61 -0
- package/lib/types/client/account-query-queue.js.map +1 -0
- package/lib/types/client/account-terminal.d.ts +6 -2
- package/lib/types/client/account-terminal.js +260 -31
- package/lib/types/client/account-terminal.js.map +1 -1
- package/lib/types/client/settings-dialog.js +65 -38
- package/lib/types/client/settings-dialog.js.map +1 -1
- package/lib/types/client/zcode-login-link-provider.d.ts +9 -0
- package/lib/types/client/zcode-login-link-provider.js +105 -0
- package/lib/types/client/zcode-login-link-provider.js.map +1 -0
- package/lib/types/client/zcode-login-link.d.ts +16 -0
- package/lib/types/client/zcode-login-link.js +194 -0
- package/lib/types/client/zcode-login-link.js.map +1 -0
- package/lib/types/host/account-models.d.mts +3 -1
- package/lib/types/host/account-models.mjs +16 -13
- package/lib/types/host/accounts.d.ts +3 -2
- package/lib/types/host/accounts.js +129 -22
- package/lib/types/host/accounts.js.map +1 -1
- package/lib/types/host/adapters.d.ts +1 -1
- package/lib/types/host/adapters.js +60 -11
- package/lib/types/host/adapters.js.map +1 -1
- package/lib/types/host/agy-models.d.ts +2 -1
- package/lib/types/host/agy-models.js +6 -6
- package/lib/types/host/agy-models.js.map +1 -1
- package/lib/types/host/agy-windows-account.d.ts +14 -0
- package/lib/types/host/agy-windows-account.js +104 -0
- package/lib/types/host/agy-windows-account.js.map +1 -0
- package/lib/types/host/authorized-catalog.js +13 -4
- package/lib/types/host/authorized-catalog.js.map +1 -1
- package/lib/types/host/claude-native-oauth.d.ts +17 -0
- package/lib/types/host/claude-native-oauth.js +272 -0
- package/lib/types/host/claude-native-oauth.js.map +1 -0
- package/lib/types/host/claude-own-route.d.ts +33 -0
- package/lib/types/host/claude-own-route.js +250 -0
- package/lib/types/host/claude-own-route.js.map +1 -0
- package/lib/types/host/cli-account-binding.d.ts +2 -1
- package/lib/types/host/cli-account-binding.js +59 -21
- package/lib/types/host/cli-account-binding.js.map +1 -1
- package/lib/types/host/codex-models.js +4 -0
- package/lib/types/host/codex-models.js.map +1 -1
- package/lib/types/host/extended-adapters.d.ts +3 -2
- package/lib/types/host/extended-adapters.js +9 -7
- package/lib/types/host/extended-adapters.js.map +1 -1
- package/lib/types/host/first-party-models.d.ts +1 -0
- package/lib/types/host/first-party-models.js +136 -47
- package/lib/types/host/first-party-models.js.map +1 -1
- package/lib/types/host/hermes-accounts.js +15 -1
- package/lib/types/host/hermes-accounts.js.map +1 -1
- package/lib/types/host/hermes-adapter.d.ts +3 -0
- package/lib/types/host/hermes-adapter.js +13 -4
- package/lib/types/host/hermes-adapter.js.map +1 -1
- package/lib/types/host/hermes-installation.js +54 -35
- package/lib/types/host/hermes-installation.js.map +1 -1
- package/lib/types/host/hermes-native-entry.py +48 -13
- package/lib/types/host/hermes-nous-refresh.py +331 -0
- package/lib/types/host/hermes-nous.d.ts +5 -1
- package/lib/types/host/hermes-nous.js +5 -5
- package/lib/types/host/hermes-nous.js.map +1 -1
- package/lib/types/host/hermes-renewal.d.ts +27 -0
- package/lib/types/host/hermes-renewal.js +292 -0
- package/lib/types/host/hermes-renewal.js.map +1 -0
- package/lib/types/host/hermes-windows-installation.d.ts +5 -0
- package/lib/types/host/hermes-windows-installation.js +91 -0
- package/lib/types/host/hermes-windows-installation.js.map +1 -0
- package/lib/types/host/index.d.ts +2 -0
- package/lib/types/host/index.js +17 -2
- package/lib/types/host/index.js.map +1 -1
- package/lib/types/host/kimi-accounts.d.ts +2 -0
- package/lib/types/host/kimi-accounts.js +4 -2
- package/lib/types/host/kimi-accounts.js.map +1 -1
- package/lib/types/host/kimi-oauth-models.d.ts +14 -0
- package/lib/types/host/kimi-oauth-models.js +246 -0
- package/lib/types/host/kimi-oauth-models.js.map +1 -0
- package/lib/types/host/mimo-metadata-cache.d.ts +22 -0
- package/lib/types/host/mimo-metadata-cache.js +121 -0
- package/lib/types/host/mimo-metadata-cache.js.map +1 -0
- package/lib/types/host/native-capability-cache.d.ts +11 -0
- package/lib/types/host/native-capability-cache.js +94 -0
- package/lib/types/host/native-capability-cache.js.map +1 -0
- package/lib/types/host/native-launch.mjs +62 -7
- package/lib/types/host/native-process.d.ts +3 -1
- package/lib/types/host/native-process.js +18 -3
- package/lib/types/host/native-process.js.map +1 -1
- package/lib/types/host/native-spawn.mjs +32 -0
- package/lib/types/host/pi-installation.d.mts +1 -1
- package/lib/types/host/pi-installation.mjs +27 -3
- package/lib/types/host/pi-omp-adapter.js +15 -1
- package/lib/types/host/pi-omp-adapter.js.map +1 -1
- package/lib/types/host/private-launch.mjs +23 -0
- package/lib/types/host/routing.js +25 -2
- package/lib/types/host/routing.js.map +1 -1
- package/lib/types/host/runtime.js +17 -5
- package/lib/types/host/runtime.js.map +1 -1
- package/lib/types/host/windows-account-bootstrap.ps1 +44 -0
- package/lib/types/host/windows-account-launch.mjs +47 -0
- package/lib/types/host/windows-account-owner.ps1 +137 -0
- package/lib/types/host/windows-account-stdio.mjs +19 -0
- package/lib/types/host/windows-account-terminal.d.ts +17 -0
- package/lib/types/host/windows-account-terminal.js +208 -0
- package/lib/types/host/windows-account-terminal.js.map +1 -0
- package/lib/types/host/windows-agy-account.ps1 +81 -0
- package/lib/types/host/windows-cli-installation.d.ts +31 -0
- package/lib/types/host/windows-cli-installation.js +157 -0
- package/lib/types/host/windows-cli-installation.js.map +1 -0
- package/lib/types/host/windows-hidden-launch.mjs +49 -0
- package/lib/types/host/windows-hidden-process.d.ts +12 -0
- package/lib/types/host/windows-hidden-process.js +116 -0
- package/lib/types/host/windows-hidden-process.js.map +1 -0
- package/lib/types/host/zcode-adapter.js +5 -1
- package/lib/types/host/zcode-adapter.js.map +1 -1
- package/lib/types/host/zcode-grok-accounts.d.ts +3 -1
- package/lib/types/host/zcode-grok-accounts.js +60 -11
- package/lib/types/host/zcode-grok-accounts.js.map +1 -1
- package/lib/types/shared/accounts.d.ts +4 -0
- package/lib/windows-account-bootstrap.ps1 +44 -0
- package/lib/windows-account-launch.mjs +47 -0
- package/lib/windows-account-owner.ps1 +137 -0
- package/lib/windows-account-stdio.mjs +19 -0
- package/lib/windows-agy-account.ps1 +81 -0
- package/lib/windows-hidden-launch.mjs +49 -0
- package/lib/zcode-resume.mjs +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Windows account PTY bootstrap. No native CLI runs until its process has been
|
|
2
|
+
// assigned to the separate lifecycle Job owner; no task sandbox is applied.
|
|
3
|
+
import { accountInput } from './windows-account-stdio.mjs'
|
|
4
|
+
import { fileURLToPath } from 'node:url'
|
|
5
|
+
import { spawnNativeProcess } from './native-spawn.mjs'
|
|
6
|
+
import { writeFileSync, existsSync } from 'node:fs'
|
|
7
|
+
import { join } from 'node:path'
|
|
8
|
+
import { setTimeout as delay } from 'node:timers/promises'
|
|
9
|
+
import { nativeLaunchArgv } from './native-launch.mjs'
|
|
10
|
+
process.umask(0o077)
|
|
11
|
+
const [directory, encoded] = process.argv.slice(2)
|
|
12
|
+
let requested
|
|
13
|
+
try { requested = JSON.parse(Buffer.from(encoded, 'base64').toString('utf8')) } catch { process.exit(1) }
|
|
14
|
+
if (!directory || !Array.isArray(requested) || !requested.length || requested.some(value => typeof value !== 'string')) process.exit(1)
|
|
15
|
+
// This exact plugin wrapper only sets umask and delegates an argv array. This
|
|
16
|
+
// helper already does both; avoid another GUI runtime losing console stdin.
|
|
17
|
+
if (requested[0] === process.execPath && requested[1] === fileURLToPath(new URL('./private-launch.mjs', import.meta.url)))
|
|
18
|
+
requested = requested.slice(2)
|
|
19
|
+
const until = Date.now() + 15_000
|
|
20
|
+
while (!existsSync(join(directory, 'ready'))) {
|
|
21
|
+
if (Date.now() >= until) process.exit(1)
|
|
22
|
+
await delay(20)
|
|
23
|
+
}
|
|
24
|
+
// Keep ConPTY alive after the native command exits so Host can dispose its
|
|
25
|
+
// native worker before closing the entire Job. Only the exit code is exposed.
|
|
26
|
+
setInterval(() => {}, 1000)
|
|
27
|
+
const recordExit = (code, signal) => {
|
|
28
|
+
const exitCode = Number.isInteger(code) ? code : 1
|
|
29
|
+
writeFileSync(join(directory, 'exit'), JSON.stringify({ exitCode, signal: signal ?? null }), { mode: 0o600 })
|
|
30
|
+
}
|
|
31
|
+
if (!existsSync(join(directory, 'cancel')) && !existsSync(join(directory, 'stop'))) {
|
|
32
|
+
try {
|
|
33
|
+
const [executable, ...argv] = nativeLaunchArgv(requested)
|
|
34
|
+
// Node-based CLI account UIs also need their own Electron stdin restored.
|
|
35
|
+
// This fixed preload is scoped to that child, never NODE_OPTIONS or Host.
|
|
36
|
+
if (executable === process.execPath && process.versions.electron)
|
|
37
|
+
argv.unshift('--import', new URL('./windows-account-stdio.mjs', import.meta.url).href)
|
|
38
|
+
// Keep the existing ConPTY handles; a GUI-subsystem parent must not cause
|
|
39
|
+
// the native CLI to present an additional Windows console window.
|
|
40
|
+
const child = spawnNativeProcess(executable, argv, { env: process.env, stdio: [accountInput, 1, 2] })
|
|
41
|
+
child.once('error', () => { process.stderr.write('CLI launch failed\r\n') })
|
|
42
|
+
child.once('close', recordExit)
|
|
43
|
+
} catch {
|
|
44
|
+
process.stderr.write('CLI launch failed\r\n')
|
|
45
|
+
recordExit(1)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
param([Parameter(Mandatory=$true)][string]$Directory, [Parameter(Mandatory=$true)][int]$HostProcessId)
|
|
2
|
+
$ErrorActionPreference = 'Stop'
|
|
3
|
+
# Fixed process ownership only: no resource, privilege, network, or filesystem limits.
|
|
4
|
+
Add-Type -TypeDefinition @'
|
|
5
|
+
using System;
|
|
6
|
+
using System.Diagnostics;
|
|
7
|
+
using System.ComponentModel;
|
|
8
|
+
using System.Runtime.InteropServices;
|
|
9
|
+
public sealed class CwnAccountJob : IDisposable {
|
|
10
|
+
[StructLayout(LayoutKind.Sequential)] struct BasicLimits { public long ProcessTime, JobTime; public uint Flags; public UIntPtr MinWorking, MaxWorking; public uint ActiveLimit; public UIntPtr Affinity; public uint Priority, Scheduling; }
|
|
11
|
+
[StructLayout(LayoutKind.Sequential)] struct Io { public ulong ReadOps, WriteOps, OtherOps, ReadBytes, WriteBytes, OtherBytes; }
|
|
12
|
+
[StructLayout(LayoutKind.Sequential)] struct ExtendedLimits { public BasicLimits Basic; public Io Io; public UIntPtr ProcessMemory, JobMemory, PeakProcessMemory, PeakJobMemory; }
|
|
13
|
+
[StructLayout(LayoutKind.Sequential)] struct Accounting { public long User, Kernel, PeriodUser, PeriodKernel; public uint PageFaults, TotalProcesses, ActiveProcesses, TerminatedProcesses; }
|
|
14
|
+
[DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)] static extern IntPtr CreateJobObject(IntPtr attr, string name);
|
|
15
|
+
[DllImport("kernel32.dll", SetLastError=true)] static extern bool SetInformationJobObject(IntPtr job, int kind, ref ExtendedLimits limits, uint size);
|
|
16
|
+
[DllImport("kernel32.dll", SetLastError=true)] static extern bool QueryInformationJobObject(IntPtr job, int kind, out Accounting info, uint size, IntPtr length);
|
|
17
|
+
[DllImport("kernel32.dll", SetLastError=true)] static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process);
|
|
18
|
+
[DllImport("kernel32.dll", SetLastError=true)] static extern bool TerminateJobObject(IntPtr job, uint code);
|
|
19
|
+
[DllImport("kernel32.dll")] static extern bool CloseHandle(IntPtr handle);
|
|
20
|
+
[DllImport("kernel32.dll")] static extern bool FreeConsole();
|
|
21
|
+
[DllImport("kernel32.dll", SetLastError=true)] static extern bool AttachConsole(uint pid);
|
|
22
|
+
[DllImport("kernel32.dll")] static extern IntPtr GetConsoleWindow();
|
|
23
|
+
[DllImport("user32.dll", SetLastError=true)] static extern uint GetWindowThreadProcessId(IntPtr window, out uint pid);
|
|
24
|
+
[DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)] static extern IntPtr GetModuleHandle(string name);
|
|
25
|
+
[DllImport("kernel32.dll", SetLastError=true)] static extern IntPtr GetProcAddress(IntPtr module, IntPtr ordinal);
|
|
26
|
+
[UnmanagedFunctionPointer(CallingConvention.Winapi)] delegate uint RealWindowOwner(IntPtr window);
|
|
27
|
+
IntPtr job; Process root;
|
|
28
|
+
public CwnAccountJob() { job=CreateJobObject(IntPtr.Zero,null); if(job==IntPtr.Zero) throw new Win32Exception(Marshal.GetLastWin32Error()); var l=new ExtendedLimits(); l.Basic.Flags=0x2000; if(!SetInformationJobObject(job,9,ref l,(uint)Marshal.SizeOf(l))) { var error=Marshal.GetLastWin32Error(); Dispose(); throw new Win32Exception(error); } }
|
|
29
|
+
public void Attach(int pid, DateTime receiptTime, DateTime earliest) { root=Process.GetProcessById(pid); var handle=root.Handle; var started=root.StartTime.ToUniversalTime(); if(started>receiptTime || started<earliest) throw new Exception("process identity changed"); if(!AssignProcessToJobObject(job,handle)) throw new Win32Exception(Marshal.GetLastWin32Error()); }
|
|
30
|
+
public static int ConsoleOwner(int pid) {
|
|
31
|
+
FreeConsole(); if(!AttachConsole((uint)pid)) throw new Win32Exception(Marshal.GetLastWin32Error());
|
|
32
|
+
try {
|
|
33
|
+
var window=GetConsoleWindow(); uint owner;
|
|
34
|
+
if(window==IntPtr.Zero || GetWindowThreadProcessId(window,out owner)==0 || owner==0) throw new Exception("console owner unavailable");
|
|
35
|
+
// Modern ConPTY gives its message-only window to the root client, not
|
|
36
|
+
// conhost: microsoft/terminal#14196. Resolve this same HWND's real owner
|
|
37
|
+
// using the maintainer's dynamic API from discussion #16447. The ordinal
|
|
38
|
+
// is not a stable public API; absence or an invalid result fails closed.
|
|
39
|
+
if(owner==(uint)pid) {
|
|
40
|
+
var module=GetModuleHandle("user32.dll");
|
|
41
|
+
var address=module==IntPtr.Zero?IntPtr.Zero:GetProcAddress(module,new IntPtr(2712));
|
|
42
|
+
if(address==IntPtr.Zero) throw new Exception("real console owner unavailable");
|
|
43
|
+
var getOwner=(RealWindowOwner)Marshal.GetDelegateForFunctionPointer(address,typeof(RealWindowOwner));
|
|
44
|
+
owner=getOwner(window);
|
|
45
|
+
}
|
|
46
|
+
if(owner==0 || owner>(uint)Int32.MaxValue || owner==(uint)pid) throw new Exception("console owner unavailable");
|
|
47
|
+
return (int)owner;
|
|
48
|
+
} finally { FreeConsole(); }
|
|
49
|
+
}
|
|
50
|
+
public string ConsoleIdentityReason { get; private set; }
|
|
51
|
+
public string ConsoleImageKind { get; private set; }
|
|
52
|
+
public bool ConsoleImageDevicePrefix { get; private set; }
|
|
53
|
+
public void AttachConsoleHost(int pid, DateTime latest, DateTime earliest) {
|
|
54
|
+
using(var p=Process.GetProcessById(pid)) {
|
|
55
|
+
var handle=p.Handle; var started=p.StartTime.ToUniversalTime();
|
|
56
|
+
var expected=System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System),"conhost.exe");
|
|
57
|
+
if(started>latest) { ConsoleIdentityReason="after-receipt"; throw new Exception("console identity changed"); }
|
|
58
|
+
if(started<earliest) { ConsoleIdentityReason="before-directory"; throw new Exception("console identity changed"); }
|
|
59
|
+
var image=p.MainModule.FileName; var leaf=System.IO.Path.GetFileName(image);
|
|
60
|
+
ConsoleImageKind=String.Equals(leaf,"conhost.exe",StringComparison.OrdinalIgnoreCase)?"conhost.exe":String.Equals(leaf,"openconsole.exe",StringComparison.OrdinalIgnoreCase)?"openconsole.exe":"other";
|
|
61
|
+
ConsoleImageDevicePrefix=image!=null && (image.StartsWith(@"\\?\") || image.StartsWith(@"\??\"));
|
|
62
|
+
if(!String.Equals(image,expected,StringComparison.OrdinalIgnoreCase)) { ConsoleIdentityReason="wrong-image"; throw new Exception("console identity changed"); }
|
|
63
|
+
if(!AssignProcessToJobObject(job,handle)) throw new Win32Exception(Marshal.GetLastWin32Error());
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
public bool RootExited { get { return root.HasExited; } }
|
|
67
|
+
public void Stop() { if(!TerminateJobObject(job,143)) throw new Win32Exception(Marshal.GetLastWin32Error()); }
|
|
68
|
+
public bool Empty { get { Accounting a; if(!QueryInformationJobObject(job,1,out a,(uint)Marshal.SizeOf(typeof(Accounting)),IntPtr.Zero)) throw new Win32Exception(Marshal.GetLastWin32Error()); return a.ActiveProcesses==0; } }
|
|
69
|
+
public void Dispose() { if(job!=IntPtr.Zero) { CloseHandle(job); job=IntPtr.Zero; } if(root!=null) root.Dispose(); }
|
|
70
|
+
}
|
|
71
|
+
'@
|
|
72
|
+
$job=$null
|
|
73
|
+
$stage='await-bootstrap'
|
|
74
|
+
$consolePid=$null
|
|
75
|
+
$consoleParentPid=$null
|
|
76
|
+
try {
|
|
77
|
+
$earliest=[System.IO.Directory]::GetCreationTimeUtc($Directory).AddSeconds(-1)
|
|
78
|
+
$pidFile=Join-Path $Directory 'pid'
|
|
79
|
+
$stopFile=Join-Path $Directory 'stop'
|
|
80
|
+
[System.IO.File]::WriteAllText((Join-Path $Directory 'owner-ready'),'owner-ready')
|
|
81
|
+
$until=[DateTime]::UtcNow.AddSeconds(15)
|
|
82
|
+
while (!(Test-Path -LiteralPath $pidFile)) {
|
|
83
|
+
if ([DateTime]::UtcNow -ge $until) { throw 'bootstrap timeout' }
|
|
84
|
+
Start-Sleep -Milliseconds 20
|
|
85
|
+
}
|
|
86
|
+
$childPid=0
|
|
87
|
+
if (![int]::TryParse([System.IO.File]::ReadAllText($pidFile),[ref]$childPid) -or $childPid -le 0) { throw 'invalid bootstrap receipt' }
|
|
88
|
+
$stage='create-job'
|
|
89
|
+
$job=New-Object CwnAccountJob
|
|
90
|
+
$stage='attach-root'
|
|
91
|
+
$job.Attach($childPid,[System.IO.File]::GetLastWriteTimeUtc($pidFile),$earliest)
|
|
92
|
+
# The ConPTY console is a sibling of the bootstrap, created by the Host.
|
|
93
|
+
# Resolve it through this exact console, then validate parent and creation
|
|
94
|
+
# identity before adding it; never enumerate/kill processes by image name.
|
|
95
|
+
$stage='resolve-console'
|
|
96
|
+
$consolePid=[CwnAccountJob]::ConsoleOwner($childPid)
|
|
97
|
+
$stage='validate-console-parent'
|
|
98
|
+
$console=Get-CimInstance Win32_Process -Filter "ProcessId=$consolePid"
|
|
99
|
+
if ($null -ne $console) { $consoleParentPid=$console.ParentProcessId }
|
|
100
|
+
if ($null -eq $console -or $console.ParentProcessId -ne $HostProcessId) { throw 'console owner mismatch' }
|
|
101
|
+
$stage='attach-console'
|
|
102
|
+
$job.AttachConsoleHost($consolePid,[System.IO.File]::GetLastWriteTimeUtc($pidFile),$earliest)
|
|
103
|
+
$stage='await-stop'
|
|
104
|
+
[System.IO.File]::WriteAllText((Join-Path $Directory 'ready'),'ready')
|
|
105
|
+
while (!$job.RootExited -and !(Test-Path -LiteralPath $stopFile)) { Start-Sleep -Milliseconds 50 }
|
|
106
|
+
$stage='stop-job'
|
|
107
|
+
$job.Stop()
|
|
108
|
+
$stage='confirm-empty'
|
|
109
|
+
$until=[DateTime]::UtcNow.AddSeconds(8)
|
|
110
|
+
while (!$job.Empty) {
|
|
111
|
+
if ([DateTime]::UtcNow -ge $until) { throw 'empty receipt timeout' }
|
|
112
|
+
Start-Sleep -Milliseconds 20
|
|
113
|
+
}
|
|
114
|
+
[System.IO.File]::WriteAllText((Join-Path $Directory 'closed'),'closed')
|
|
115
|
+
exit 0
|
|
116
|
+
} catch {
|
|
117
|
+
# Fixed stage and numeric metadata only; no exception text/argv/environment.
|
|
118
|
+
$failure=@{ stage=$stage; hostPid=$HostProcessId; ownerPid=$PID }
|
|
119
|
+
if ($null -ne $consolePid) { $failure.consolePid=$consolePid }
|
|
120
|
+
if ($null -ne $consoleParentPid) { $failure.consoleParentPid=$consoleParentPid }
|
|
121
|
+
if ($null -ne $job -and $job.ConsoleIdentityReason -in @('before-directory','after-receipt','wrong-image')) {
|
|
122
|
+
$failure.identityReason=$job.ConsoleIdentityReason
|
|
123
|
+
if ($job.ConsoleImageKind -in @('conhost.exe','openconsole.exe','other')) {
|
|
124
|
+
$failure.imageKind=$job.ConsoleImageKind
|
|
125
|
+
$failure.imageDevicePrefix=$job.ConsoleImageDevicePrefix
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
$errorObject=$_.Exception
|
|
129
|
+
while ($null -ne $errorObject) {
|
|
130
|
+
if ($errorObject -is [System.ComponentModel.Win32Exception]) { $failure.win32Code=$errorObject.NativeErrorCode; break }
|
|
131
|
+
$errorObject=$errorObject.InnerException
|
|
132
|
+
}
|
|
133
|
+
try { [System.IO.File]::WriteAllText((Join-Path $Directory 'failure'),($failure | ConvertTo-Json -Compress)) } catch {}
|
|
134
|
+
# Fixed classification only: never emit native exception/context/environment.
|
|
135
|
+
[Console]::Error.WriteLine('Windows account process ownership failed')
|
|
136
|
+
exit 2
|
|
137
|
+
} finally { if ($null -ne $job) { $job.Dispose() } }
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Imported only by the Windows account-terminal runtime and its Electron CLI
|
|
2
|
+
// child. Electron attaches stdout/stderr to the parent console, but its GUI
|
|
3
|
+
// executable can leave fd 0 mapped to NUL. Reopen this already-owned console;
|
|
4
|
+
// do not redirect stdin for task processes or change the shared Host.
|
|
5
|
+
import { openSync, closeSync } from 'node:fs'
|
|
6
|
+
import { isatty, ReadStream } from 'node:tty'
|
|
7
|
+
export let accountInput = 0
|
|
8
|
+
if (process.platform === 'win32' && !isatty(0)) {
|
|
9
|
+
try {
|
|
10
|
+
accountInput = openSync('\\\\.\\CONIN$', 'r+')
|
|
11
|
+
if (!isatty(accountInput)) throw new Error('not a console')
|
|
12
|
+
const input = new ReadStream(accountInput)
|
|
13
|
+
Object.defineProperty(process, 'stdin', { value: input, configurable: true })
|
|
14
|
+
process.once('exit', () => { try { closeSync(accountInput) } catch {} })
|
|
15
|
+
} catch {
|
|
16
|
+
if (accountInput) { try { closeSync(accountInput) } catch {} }
|
|
17
|
+
throw new Error('Windows account console input unavailable')
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Read only Antigravity's own native Windows credential. Never emit its blob.
|
|
2
|
+
$ErrorActionPreference = 'Stop'
|
|
3
|
+
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)
|
|
4
|
+
try {
|
|
5
|
+
Add-Type @'
|
|
6
|
+
using System;
|
|
7
|
+
using System.Runtime.InteropServices;
|
|
8
|
+
using System.Text;
|
|
9
|
+
public static class CwnAgyCredential {
|
|
10
|
+
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] struct Credential {
|
|
11
|
+
public uint Flags, Type;
|
|
12
|
+
public string TargetName, Comment;
|
|
13
|
+
public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten;
|
|
14
|
+
public uint CredentialBlobSize;
|
|
15
|
+
public IntPtr CredentialBlob;
|
|
16
|
+
public uint Persist, AttributeCount;
|
|
17
|
+
public IntPtr Attributes;
|
|
18
|
+
public string TargetAlias, UserName;
|
|
19
|
+
}
|
|
20
|
+
[DllImport("advapi32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
|
|
21
|
+
static extern bool CredRead(string target, uint type, uint flags, out IntPtr value);
|
|
22
|
+
[DllImport("advapi32.dll")] static extern void CredFree(IntPtr value);
|
|
23
|
+
public static string Read() {
|
|
24
|
+
IntPtr value;
|
|
25
|
+
if (!CredRead("gemini:antigravity", 1, 0, out value)) {
|
|
26
|
+
if (Marshal.GetLastWin32Error() == 1168) return null;
|
|
27
|
+
throw new Exception("Credential store unavailable");
|
|
28
|
+
}
|
|
29
|
+
byte[] bytes = null;
|
|
30
|
+
try {
|
|
31
|
+
var credential = (Credential)Marshal.PtrToStructure(value, typeof(Credential));
|
|
32
|
+
if (credential.CredentialBlobSize > 65536) throw new Exception("Invalid credential");
|
|
33
|
+
bytes = new byte[credential.CredentialBlobSize];
|
|
34
|
+
Marshal.Copy(credential.CredentialBlob, bytes, 0, bytes.Length);
|
|
35
|
+
return bytes.Length > 1 && bytes[1] == 0
|
|
36
|
+
? new UnicodeEncoding(false, false, true).GetString(bytes)
|
|
37
|
+
: new UTF8Encoding(false, true).GetString(bytes);
|
|
38
|
+
} finally {
|
|
39
|
+
if (bytes != null) Array.Clear(bytes, 0, bytes.Length);
|
|
40
|
+
CredFree(value);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
'@
|
|
45
|
+
$raw = [CwnAgyCredential]::Read()
|
|
46
|
+
if ($null -eq $raw) { @{ state = 'unconfigured' } | ConvertTo-Json -Compress; exit 0 }
|
|
47
|
+
$account = $raw | ConvertFrom-Json
|
|
48
|
+
$raw = $null
|
|
49
|
+
if ($account.auth_method -ne 'consumer' -or -not $account.token) {
|
|
50
|
+
@{ state = 'unknown' } | ConvertTo-Json -Compress; exit 0
|
|
51
|
+
}
|
|
52
|
+
$active = $false
|
|
53
|
+
if ($account.token.access_token -is [string] -and $account.token.access_token.Trim()) {
|
|
54
|
+
try { $active = [DateTimeOffset]::Parse($account.token.expiry) -gt [DateTimeOffset]::UtcNow } catch {}
|
|
55
|
+
}
|
|
56
|
+
$refreshable = $account.token.refresh_token -is [string] -and $account.token.refresh_token.Trim().Length -gt 0
|
|
57
|
+
if (-not $active -and -not $refreshable) {
|
|
58
|
+
@{ state = 'unauthenticated' } | ConvertTo-Json -Compress; exit 0
|
|
59
|
+
}
|
|
60
|
+
$result = @{ state = 'authenticated' }
|
|
61
|
+
if ($account.id_token -is [string] -and $account.id_token.Length -le 32768 -and $account.id_token -match '^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$') {
|
|
62
|
+
$encoded = $account.id_token.Split('.')[1].Replace('-','+').Replace('_','/')
|
|
63
|
+
$encoded = $encoded.PadRight($encoded.Length + ((4 - $encoded.Length % 4) % 4), '=')
|
|
64
|
+
$bytes = [Convert]::FromBase64String($encoded)
|
|
65
|
+
try { $claims = [Text.Encoding]::UTF8.GetString($bytes) | ConvertFrom-Json }
|
|
66
|
+
finally { [Array]::Clear($bytes, 0, $bytes.Length) }
|
|
67
|
+
if ($claims.iss -in @('accounts.google.com', 'https://accounts.google.com') -and $claims.sub -is [string] -and $claims.sub -match '^[A-Za-z0-9_-]{6,128}$') {
|
|
68
|
+
$hash = [Security.Cryptography.SHA256]::Create()
|
|
69
|
+
$principal = [Text.Encoding]::UTF8.GetBytes('google:' + $claims.sub)
|
|
70
|
+
try { $result.principalHash = ([BitConverter]::ToString($hash.ComputeHash($principal))).Replace('-','').ToLowerInvariant() }
|
|
71
|
+
finally { [Array]::Clear($principal, 0, $principal.Length); $hash.Dispose() }
|
|
72
|
+
if ($claims.email -is [string] -and $claims.email.Length -le 254 -and $claims.email -match '^[^\s<>@]+@[^\s<>@]+\.[^\s<>@]+$') { $result.email = $claims.email }
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
$account = $null; $claims = $null
|
|
76
|
+
$result | ConvertTo-Json -Compress
|
|
77
|
+
} catch {
|
|
78
|
+
# Neither exception strings nor credential fragments cross the process boundary.
|
|
79
|
+
@{ state = 'unavailable' } | ConvertTo-Json -Compress
|
|
80
|
+
exit 1
|
|
81
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// A GUI-subsystem Electron root avoids Windows Terminal's console delegation.
|
|
2
|
+
// The enclosing Harness Job still owns this root and every native descendant.
|
|
3
|
+
import { Socket } from 'node:net'
|
|
4
|
+
import { forwardNativeStdio, spawnNativeProcess } from './native-spawn.mjs'
|
|
5
|
+
|
|
6
|
+
// Pinned Harness 0.2.0-rc.2 public control contract. This helper must remain
|
|
7
|
+
// self-contained: an ordinary child does not use the Host's SDK module loader.
|
|
8
|
+
const marker = process.env.DSH_SUBPROCESS_CONTROL
|
|
9
|
+
delete process.env.DSH_SUBPROCESS_CONTROL
|
|
10
|
+
if (marker !== 'pipe') throw new Error('Windows background control channel is unavailable')
|
|
11
|
+
const control = new Socket({ fd: 7, readable: true, writable: true, allowHalfOpen: true })
|
|
12
|
+
let child, sent = false
|
|
13
|
+
function receipt(value) {
|
|
14
|
+
if (sent) return
|
|
15
|
+
sent = true
|
|
16
|
+
control.end(JSON.stringify(value) + '\n', () => control.destroy())
|
|
17
|
+
}
|
|
18
|
+
control.on('error', () => {
|
|
19
|
+
child?.kill('SIGTERM')
|
|
20
|
+
process.exitCode = 1
|
|
21
|
+
})
|
|
22
|
+
try {
|
|
23
|
+
const [encoded, executable, ...argv] = process.argv.slice(2)
|
|
24
|
+
const restore = JSON.parse(encoded)
|
|
25
|
+
if (!restore || !Object.hasOwn(restore, 'nodeEnv') ||
|
|
26
|
+
(restore.nodeEnv !== null && typeof restore.nodeEnv !== 'string') || !executable)
|
|
27
|
+
throw new Error('Invalid fixed bootstrap arguments')
|
|
28
|
+
if (restore.privateUmask === true) process.umask(0o077)
|
|
29
|
+
// ELECTRON_RUN_AS_NODE belongs only to this GUI bootstrap. Preserve the
|
|
30
|
+
// original target environment, including an explicit deletion of that value.
|
|
31
|
+
const env = { ...process.env }
|
|
32
|
+
for (const key of Object.keys(env))
|
|
33
|
+
if (key.toUpperCase() === 'ELECTRON_RUN_AS_NODE') delete env[key]
|
|
34
|
+
if (restore.nodeEnv !== null) env.ELECTRON_RUN_AS_NODE = restore.nodeEnv
|
|
35
|
+
child = spawnNativeProcess(executable, argv, { env, stdio: ['pipe', 'pipe', 'pipe'], detached: false })
|
|
36
|
+
forwardNativeStdio(child)
|
|
37
|
+
child.once('error', error => receipt({
|
|
38
|
+
kind: 'spawn-error',
|
|
39
|
+
code: ['ENOENT', 'EACCES', 'ENOEXEC', 'EINVAL'].includes(error.code) ? error.code : 'UNKNOWN',
|
|
40
|
+
}))
|
|
41
|
+
// A descendant may keep these pipes open after the native parent exits.
|
|
42
|
+
// Report its actual exit now; keep forwarding bytes until the pipes close.
|
|
43
|
+
// The Host's original Job remains responsible for the entire process range.
|
|
44
|
+
child.once('exit', (exitCode, signal) => receipt({ kind: 'exit', exitCode, signal }))
|
|
45
|
+
for (const signal of ['SIGTERM', 'SIGINT'])
|
|
46
|
+
process.on(signal, () => child.kill(signal))
|
|
47
|
+
} catch {
|
|
48
|
+
receipt({ kind: 'spawn-error', code: 'UNKNOWN' })
|
|
49
|
+
}
|
package/lib/zcode-resume.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// ZCode ignores configured defaults on --resume. Apply the selected native model
|
|
2
2
|
// through metadata RPC, close the server completely, then run the original argv.
|
|
3
3
|
// The Host owns the surrounding Seatbelt and process range; never detach or shell.
|
|
4
|
-
import {
|
|
4
|
+
import { spawnNativeProcess } from './native-spawn.mjs'
|
|
5
5
|
import { constants } from 'node:fs'
|
|
6
6
|
import { open, lstat, realpath, unlink } from 'node:fs/promises'
|
|
7
7
|
import { dirname, isAbsolute, resolve } from 'node:path'
|
|
@@ -25,7 +25,7 @@ const checkActive = () => {
|
|
|
25
25
|
|
|
26
26
|
function start(argv, project, pipes) {
|
|
27
27
|
checkActive()
|
|
28
|
-
const child =
|
|
28
|
+
const child = spawnNativeProcess(argv[0], argv.slice(1), {
|
|
29
29
|
cwd: project,
|
|
30
30
|
env: process.env,
|
|
31
31
|
detached: false,
|