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,208 @@
|
|
|
1
|
+
import { mkdtemp, readFile, writeFile, rm } from 'node:fs/promises';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { setTimeout as delay } from 'node:timers/promises';
|
|
6
|
+
import { ProcessCleanupUnconfirmedError } from "./process.js";
|
|
7
|
+
/** A fixed diagnostic; never derived from PowerShell or native output. */
|
|
8
|
+
export class WindowsAccountTerminalError extends Error {
|
|
9
|
+
constructor() {
|
|
10
|
+
super('Windows 账号终端托管不可用,请检查 PowerShell 后重试');
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/** ConPTY publishes pid=0 during async allocation in the pinned Windows SDK.
|
|
14
|
+
* Attach a waiting bootstrap to a lifecycle-only Job before allowing the CLI to
|
|
15
|
+
* spawn. The separate owner is itself held by the Host's ordinary subprocess
|
|
16
|
+
* Job, so closing/crashing the Host also closes the account process range.
|
|
17
|
+
*/
|
|
18
|
+
export async function spawnAccountTerminal(backend, spec, options = {}) {
|
|
19
|
+
if ((options.platform ?? process.platform) !== 'win32')
|
|
20
|
+
return backend.spawnTerminal(spec);
|
|
21
|
+
spec.signal?.throwIfAborted();
|
|
22
|
+
const directory = await mkdtemp(join(tmpdir(), 'cwn-account-job-'));
|
|
23
|
+
const windows = process.env.SystemRoot ?? 'C:\\Windows';
|
|
24
|
+
let terminal;
|
|
25
|
+
const owner = await (async () => {
|
|
26
|
+
try {
|
|
27
|
+
return backend.spawn({
|
|
28
|
+
argv: [
|
|
29
|
+
join(windows, 'System32/WindowsPowerShell/v1.0/powershell.exe'),
|
|
30
|
+
'-NoLogo',
|
|
31
|
+
'-NoProfile',
|
|
32
|
+
'-NonInteractive',
|
|
33
|
+
'-File',
|
|
34
|
+
fileURLToPath(new URL('./windows-account-owner.ps1', import.meta.url)),
|
|
35
|
+
'-HostProcessId',
|
|
36
|
+
String(process.pid),
|
|
37
|
+
'-Directory',
|
|
38
|
+
directory,
|
|
39
|
+
],
|
|
40
|
+
cwd: spec.cwd,
|
|
41
|
+
stdio: { stdin: 'ignore', stdout: 'pipe', stderr: 'pipe' },
|
|
42
|
+
graceMs: 1000,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
await rm(directory, { recursive: true, force: true });
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
})();
|
|
50
|
+
void owner.done.catch(() => undefined);
|
|
51
|
+
owner.stdout?.resume();
|
|
52
|
+
owner.stderr?.resume();
|
|
53
|
+
let cleanup;
|
|
54
|
+
const exists = async (name) => {
|
|
55
|
+
try {
|
|
56
|
+
return (await readFile(join(directory, name), 'utf8')).trim() === name;
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
const terminate = () => (cleanup ??= (async () => {
|
|
63
|
+
let stage = 'receipt';
|
|
64
|
+
try {
|
|
65
|
+
// Cancellation before the handshake must still let the owner adopt the
|
|
66
|
+
// bootstrap/console, while preventing it from launching the native CLI.
|
|
67
|
+
await writeFile(join(directory, 'cancel'), 'cancel', { mode: 0o600 });
|
|
68
|
+
const adoptedUntil = Date.now() + (options.cleanupMs ?? 9000);
|
|
69
|
+
while (!(await exists('ready'))) {
|
|
70
|
+
if (Date.now() >= adoptedUntil)
|
|
71
|
+
throw new ProcessCleanupUnconfirmedError();
|
|
72
|
+
await delay(25);
|
|
73
|
+
}
|
|
74
|
+
// Dispose ConPTY while the bootstrap is still alive. With the pinned
|
|
75
|
+
// node-pty provider, killing the Job first bypasses its worker disposal.
|
|
76
|
+
// Native exit receipts keep the bootstrap alive for this same reason.
|
|
77
|
+
const disposal = terminal?.terminate().then(() => true, () => false);
|
|
78
|
+
if (disposal)
|
|
79
|
+
await Promise.race([disposal, delay(options.terminalExitMs ?? 2500)]);
|
|
80
|
+
await writeFile(join(directory, 'stop'), 'stop', { mode: 0o600 });
|
|
81
|
+
const deadline = Date.now() + (options.cleanupMs ?? 9000);
|
|
82
|
+
while (!(await exists('closed'))) {
|
|
83
|
+
if (Date.now() >= deadline)
|
|
84
|
+
throw new ProcessCleanupUnconfirmedError();
|
|
85
|
+
await delay(25);
|
|
86
|
+
}
|
|
87
|
+
// The receipt follows ActiveProcesses == 0, not just the root's exit.
|
|
88
|
+
stage = 'terminal';
|
|
89
|
+
if (disposal && !(await Promise.race([disposal, delay(options.terminalExitMs ?? 2500, false)])))
|
|
90
|
+
throw new ProcessCleanupUnconfirmedError();
|
|
91
|
+
stage = 'owner';
|
|
92
|
+
if (!(await owner.waitForExit()))
|
|
93
|
+
throw new ProcessCleanupUnconfirmedError();
|
|
94
|
+
await owner.done;
|
|
95
|
+
stage = 'directory';
|
|
96
|
+
await rm(directory, { recursive: true, force: true });
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
cleanup = undefined;
|
|
100
|
+
throw Object.assign(new ProcessCleanupUnconfirmedError(), { stage });
|
|
101
|
+
}
|
|
102
|
+
})());
|
|
103
|
+
try {
|
|
104
|
+
// Compile/validate the fixed owner before allocating any ConPTY resources.
|
|
105
|
+
const ownerUntil = Date.now() + (options.handshakeMs ?? 15_000);
|
|
106
|
+
while (!(await exists('owner-ready'))) {
|
|
107
|
+
spec.signal?.throwIfAborted();
|
|
108
|
+
if (Date.now() >= ownerUntil)
|
|
109
|
+
throw new Error('Windows account owner handshake timed out');
|
|
110
|
+
await Promise.race([
|
|
111
|
+
delay(25),
|
|
112
|
+
owner.done.then(() => {
|
|
113
|
+
throw new Error('Windows account owner ended');
|
|
114
|
+
}),
|
|
115
|
+
]);
|
|
116
|
+
}
|
|
117
|
+
spec.signal?.throwIfAborted();
|
|
118
|
+
terminal = await backend.spawnTerminal({
|
|
119
|
+
...spec,
|
|
120
|
+
signal: undefined,
|
|
121
|
+
argv: [
|
|
122
|
+
join(windows, 'System32/WindowsPowerShell/v1.0/powershell.exe'),
|
|
123
|
+
'-NoLogo',
|
|
124
|
+
'-NoProfile',
|
|
125
|
+
'-NonInteractive',
|
|
126
|
+
'-File',
|
|
127
|
+
fileURLToPath(new URL('./windows-account-bootstrap.ps1', import.meta.url)),
|
|
128
|
+
'-Directory',
|
|
129
|
+
directory,
|
|
130
|
+
'-RuntimePath',
|
|
131
|
+
process.execPath,
|
|
132
|
+
'-LaunchPath',
|
|
133
|
+
fileURLToPath(new URL('./windows-account-launch.mjs', import.meta.url)),
|
|
134
|
+
'-ArgumentsBase64',
|
|
135
|
+
Buffer.from(JSON.stringify(spec.argv), 'utf8').toString('base64'),
|
|
136
|
+
],
|
|
137
|
+
env: { ...spec.env, ELECTRON_RUN_AS_NODE: '1' },
|
|
138
|
+
});
|
|
139
|
+
void terminal.done.catch(() => undefined);
|
|
140
|
+
const until = Date.now() + (options.handshakeMs ?? 15_000);
|
|
141
|
+
while (!(await exists('ready'))) {
|
|
142
|
+
spec.signal?.throwIfAborted();
|
|
143
|
+
if (Date.now() >= until)
|
|
144
|
+
throw new Error('Windows account terminal handshake timed out');
|
|
145
|
+
await Promise.race([
|
|
146
|
+
delay(25),
|
|
147
|
+
owner.done.then(() => {
|
|
148
|
+
throw new Error('Windows account owner ended');
|
|
149
|
+
}),
|
|
150
|
+
]);
|
|
151
|
+
}
|
|
152
|
+
const current = terminal;
|
|
153
|
+
const done = (async () => {
|
|
154
|
+
for (;;) {
|
|
155
|
+
try {
|
|
156
|
+
const receipt = JSON.parse(await readFile(join(directory, 'exit'), 'utf8'));
|
|
157
|
+
if (Number.isInteger(receipt.exitCode))
|
|
158
|
+
return { exitCode: receipt.exitCode, signal: null };
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
/* An interrupted bootstrap retains the SDK outcome. */
|
|
162
|
+
}
|
|
163
|
+
const outcome = await Promise.race([current.done, delay(50, undefined)]);
|
|
164
|
+
if (outcome)
|
|
165
|
+
return outcome;
|
|
166
|
+
}
|
|
167
|
+
})();
|
|
168
|
+
void done.catch(() => undefined);
|
|
169
|
+
return {
|
|
170
|
+
pid: Number(await readFile(join(directory, 'pid'), 'utf8')),
|
|
171
|
+
output: current.output,
|
|
172
|
+
done,
|
|
173
|
+
write: (data) => current.write(data),
|
|
174
|
+
resize: (cols, rows) => current.resize(cols, rows),
|
|
175
|
+
inspectForeground: () => current.inspectForeground(),
|
|
176
|
+
inspectActivity: () => current.inspectActivity(),
|
|
177
|
+
signalForeground: (signal) => current.signalForeground(signal),
|
|
178
|
+
terminate,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
if (terminal) {
|
|
183
|
+
// A cancellation can precede ready: the bootstrap keeps waiting until
|
|
184
|
+
// the owner adopts its console/Job, then observes stop without running
|
|
185
|
+
// the CLI. Require the same empty-range receipt as a normal close.
|
|
186
|
+
try {
|
|
187
|
+
await terminate();
|
|
188
|
+
}
|
|
189
|
+
catch (failure) {
|
|
190
|
+
owner.terminate();
|
|
191
|
+
await terminal.terminate().catch(() => undefined);
|
|
192
|
+
throw failure;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
// No terminal was allocated; only the ordinary managed owner exists.
|
|
197
|
+
await writeFile(join(directory, 'stop'), 'stop', { mode: 0o600 });
|
|
198
|
+
owner.terminate();
|
|
199
|
+
if (!(await owner.waitForExit()))
|
|
200
|
+
throw new ProcessCleanupUnconfirmedError();
|
|
201
|
+
await rm(directory, { recursive: true, force: true });
|
|
202
|
+
}
|
|
203
|
+
if (spec.signal?.aborted)
|
|
204
|
+
throw error;
|
|
205
|
+
throw new WindowsAccountTerminalError();
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=windows-account-terminal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"windows-account-terminal.js","sourceRoot":"","sources":["../../../src/host/windows-account-terminal.ts"],"names":[],"mappings":"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"}
|
|
@@ -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,31 @@
|
|
|
1
|
+
export declare class WindowsCliInstallationError extends Error {
|
|
2
|
+
readonly installed: boolean;
|
|
3
|
+
readonly code = "CLI_INSTALLATION_UNAVAILABLE";
|
|
4
|
+
constructor(message: string, installed?: boolean);
|
|
5
|
+
}
|
|
6
|
+
type WindowsEnvironment = {
|
|
7
|
+
home?: string;
|
|
8
|
+
env?: NodeJS.ProcessEnv;
|
|
9
|
+
};
|
|
10
|
+
/** Fixed installer locations only; never scan arbitrary drives or select a venv by recency. */
|
|
11
|
+
export declare function windowsCliCandidates(cli: 'codex' | 'hermes', options?: WindowsEnvironment): string[];
|
|
12
|
+
/** A residue is not a runnable installation and is not evidence of an account. */
|
|
13
|
+
export declare function hasWindowsHermesInstallDirectory(options?: WindowsEnvironment): boolean;
|
|
14
|
+
/** Validate an automatically discovered npm shim against Codex's own package, not just its name. */
|
|
15
|
+
export declare function validateWindowsCodexNpmEntry(path: string): string;
|
|
16
|
+
export declare function presentWindowsCliCandidate(cli: 'codex' | 'hermes', options?: WindowsEnvironment): string | undefined;
|
|
17
|
+
/** Query current-user registered packages, never guess the newest WindowsApps directory. */
|
|
18
|
+
export declare const CODEX_APPX_QUERY = "$ErrorActionPreference='Stop'; [Console]::OutputEncoding=[Text.UTF8Encoding]::new($false); $p=@(Get-AppxPackage -Name 'OpenAI.Codex'); if($p.Count -eq 0){'null';exit 0}; if($p.Count -ne 1){throw 'Ambiguous Codex package'}; $v=$p[0]; [ordered]@{name=$v.Name;family=$v.PackageFamilyName;fullName=$v.PackageFullName;publisher=$v.Publisher;signature=[string]$v.SignatureKind;status=[string]$v.Status;location=$v.InstallLocation}|ConvertTo-Json -Compress";
|
|
19
|
+
export interface CodexAppxRecord {
|
|
20
|
+
name: string;
|
|
21
|
+
family: string;
|
|
22
|
+
fullName: string;
|
|
23
|
+
publisher: string;
|
|
24
|
+
signature: string;
|
|
25
|
+
status: string;
|
|
26
|
+
location: string;
|
|
27
|
+
}
|
|
28
|
+
/** Exported separately for synthetic identity/relocation tests; no process or account access. */
|
|
29
|
+
export declare function codexAppxExecutable(raw: string, validateFile?: (path: string) => string): string | undefined;
|
|
30
|
+
export declare function findWindowsCodexAppx(capture: (argv: string[], cwd: string) => Promise<string>, signal: AbortSignal, env?: NodeJS.ProcessEnv): Promise<string | undefined>;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { closeSync, existsSync, fstatSync, lstatSync, openSync, readFileSync, readSync, realpathSync, statSync, } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { dirname, isAbsolute, join, resolve, win32 } from 'node:path';
|
|
4
|
+
import { resolveNativeEntry } from './native-launch.mjs';
|
|
5
|
+
export class WindowsCliInstallationError extends Error {
|
|
6
|
+
installed;
|
|
7
|
+
code = 'CLI_INSTALLATION_UNAVAILABLE';
|
|
8
|
+
constructor(message, installed = false) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.installed = installed;
|
|
11
|
+
this.name = 'WindowsCliInstallationError';
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const unavailableCodex = () => new WindowsCliInstallationError('Codex Windows 应用包入口无法确认,请检查安装', true);
|
|
15
|
+
function directory(env, name, fallback) {
|
|
16
|
+
const value = env[name]?.trim() || fallback;
|
|
17
|
+
if (!isAbsolute(value))
|
|
18
|
+
throw new WindowsCliInstallationError('Windows CLI 安装目录配置无效');
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
/** Fixed installer locations only; never scan arbitrary drives or select a venv by recency. */
|
|
22
|
+
export function windowsCliCandidates(cli, options = {}) {
|
|
23
|
+
const env = options.env ?? process.env, home = options.home ?? homedir();
|
|
24
|
+
if (cli === 'codex') {
|
|
25
|
+
const npm = join(directory(env, 'APPDATA', join(home, 'AppData', 'Roaming')), 'npm');
|
|
26
|
+
return [join(npm, 'codex.cmd')];
|
|
27
|
+
}
|
|
28
|
+
const root = join(directory(env, 'LOCALAPPDATA', join(home, 'AppData', 'Local')), 'hermes');
|
|
29
|
+
return [
|
|
30
|
+
join(root, 'bin', 'hermes.exe'),
|
|
31
|
+
join(root, 'bin', 'hermes.cmd'),
|
|
32
|
+
join(root, 'hermes-agent', 'venv', 'Scripts', 'hermes.exe'),
|
|
33
|
+
];
|
|
34
|
+
}
|
|
35
|
+
/** A residue is not a runnable installation and is not evidence of an account. */
|
|
36
|
+
export function hasWindowsHermesInstallDirectory(options = {}) {
|
|
37
|
+
const env = options.env ?? process.env, home = options.home ?? homedir();
|
|
38
|
+
return existsSync(join(directory(env, 'LOCALAPPDATA', join(home, 'AppData', 'Local')), 'hermes'));
|
|
39
|
+
}
|
|
40
|
+
function nativePe(path) {
|
|
41
|
+
const canonical = realpathSync(path), fd = openSync(canonical, 'r');
|
|
42
|
+
try {
|
|
43
|
+
const info = fstatSync(fd), head = Buffer.alloc(64), signature = Buffer.alloc(4);
|
|
44
|
+
if (!info.isFile() || readSync(fd, head, 0, 64, 0) !== 64 || head.toString('ascii', 0, 2) !== 'MZ')
|
|
45
|
+
throw new Error('Not a native PE file');
|
|
46
|
+
const offset = head.readUInt32LE(0x3c);
|
|
47
|
+
if (offset < 64 ||
|
|
48
|
+
offset + 4 > info.size ||
|
|
49
|
+
readSync(fd, signature, 0, 4, offset) !== 4 ||
|
|
50
|
+
signature.toString('hex') !== '50450000')
|
|
51
|
+
throw new Error('Invalid PE signature');
|
|
52
|
+
return canonical;
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
closeSync(fd);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/** Validate an automatically discovered npm shim against Codex's own package, not just its name. */
|
|
59
|
+
export function validateWindowsCodexNpmEntry(path) {
|
|
60
|
+
try {
|
|
61
|
+
const root = join(dirname(path), 'node_modules', '@openai', 'codex');
|
|
62
|
+
const manifestPath = join(root, 'package.json');
|
|
63
|
+
if (statSync(manifestPath).size > 128 * 1024)
|
|
64
|
+
throw new Error('Oversized package metadata');
|
|
65
|
+
const data = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
66
|
+
const bin = typeof data.bin === 'string' ? data.bin : data.bin?.codex;
|
|
67
|
+
if (data.name !== '@openai/codex' ||
|
|
68
|
+
typeof bin !== 'string' ||
|
|
69
|
+
isAbsolute(bin) ||
|
|
70
|
+
bin.split(/[\\/]/).includes('..'))
|
|
71
|
+
throw new Error('Mismatched package identity');
|
|
72
|
+
const entry = resolveNativeEntry(path, 'win32');
|
|
73
|
+
if (realpathSync(entry) !== realpathSync(resolve(root, bin)))
|
|
74
|
+
throw new Error('Mismatched package entry');
|
|
75
|
+
return path;
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
throw new WindowsCliInstallationError('Codex npm 安装入口无法确认,请检查安装', true);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
export function presentWindowsCliCandidate(cli, options = {}) {
|
|
82
|
+
for (const path of windowsCliCandidates(cli, options)) {
|
|
83
|
+
try {
|
|
84
|
+
lstatSync(path);
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
if (['ENOENT', 'ENOTDIR'].includes(error.code ?? ''))
|
|
88
|
+
continue;
|
|
89
|
+
throw new WindowsCliInstallationError('Windows CLI 安装入口无法读取,请检查安装', true);
|
|
90
|
+
}
|
|
91
|
+
if (cli === 'codex')
|
|
92
|
+
return validateWindowsCodexNpmEntry(path);
|
|
93
|
+
try {
|
|
94
|
+
const entry = resolveNativeEntry(path, 'win32');
|
|
95
|
+
if (/\.exe$/i.test(entry))
|
|
96
|
+
nativePe(entry);
|
|
97
|
+
else if (entry !== path || !/\.cmd$/i.test(entry))
|
|
98
|
+
throw new Error('Unsupported Hermes entry');
|
|
99
|
+
// Fixed Python cmd launchers are statically checked by resolveNativeEntry;
|
|
100
|
+
// the existing Hermes verifier preserves the installer's own interpreter.
|
|
101
|
+
return path;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
throw new WindowsCliInstallationError('Hermes Windows 安装入口无法确认,请检查安装', true);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
const codexFamily = 'OpenAI.Codex_2p2nqsd0c76g0';
|
|
110
|
+
const codexPublisher = 'CN=50BDFD77-8903-4850-9FFE-6E8522F64D5B';
|
|
111
|
+
/** Query current-user registered packages, never guess the newest WindowsApps directory. */
|
|
112
|
+
export const CODEX_APPX_QUERY = `$ErrorActionPreference='Stop'; [Console]::OutputEncoding=[Text.UTF8Encoding]::new($false); $p=@(Get-AppxPackage -Name 'OpenAI.Codex'); if($p.Count -eq 0){'null';exit 0}; if($p.Count -ne 1){throw 'Ambiguous Codex package'}; $v=$p[0]; [ordered]@{name=$v.Name;family=$v.PackageFamilyName;fullName=$v.PackageFullName;publisher=$v.Publisher;signature=[string]$v.SignatureKind;status=[string]$v.Status;location=$v.InstallLocation}|ConvertTo-Json -Compress`;
|
|
113
|
+
/** Exported separately for synthetic identity/relocation tests; no process or account access. */
|
|
114
|
+
export function codexAppxExecutable(raw, validateFile = nativePe) {
|
|
115
|
+
try {
|
|
116
|
+
const value = JSON.parse(raw.trim());
|
|
117
|
+
if (value === null)
|
|
118
|
+
return undefined;
|
|
119
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
120
|
+
throw new Error('Invalid package record');
|
|
121
|
+
const p = value;
|
|
122
|
+
if (p.name !== 'OpenAI.Codex' ||
|
|
123
|
+
p.family !== codexFamily ||
|
|
124
|
+
p.publisher !== codexPublisher ||
|
|
125
|
+
p.signature !== 'Store' ||
|
|
126
|
+
p.status !== 'Ok' ||
|
|
127
|
+
typeof p.fullName !== 'string' ||
|
|
128
|
+
!/^OpenAI\.Codex_\d+(?:\.\d+){3}_(?:x64|arm64|x86)__2p2nqsd0c76g0$/.test(p.fullName) ||
|
|
129
|
+
typeof p.location !== 'string' ||
|
|
130
|
+
!win32.isAbsolute(p.location) ||
|
|
131
|
+
p.location.includes('\0') ||
|
|
132
|
+
p.location.startsWith('\\\\') ||
|
|
133
|
+
win32.basename(p.location).toLowerCase() !== p.fullName.toLowerCase())
|
|
134
|
+
throw new Error('Unverified package identity');
|
|
135
|
+
const candidate = win32.join(p.location, 'app', 'resources', 'codex.exe');
|
|
136
|
+
const canonical = validateFile(candidate);
|
|
137
|
+
// A registered package's CLI must stay in that package; never follow a swapped link elsewhere.
|
|
138
|
+
if (win32.normalize(canonical).toLowerCase() !== win32.normalize(candidate).toLowerCase())
|
|
139
|
+
throw new Error('Redirected package entry');
|
|
140
|
+
return canonical;
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
throw unavailableCodex();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
export async function findWindowsCodexAppx(capture, signal, env = process.env) {
|
|
147
|
+
signal.throwIfAborted();
|
|
148
|
+
const windows = env.SystemRoot || env.WINDIR || 'C:\\Windows';
|
|
149
|
+
if (!win32.isAbsolute(windows))
|
|
150
|
+
throw new WindowsCliInstallationError('Windows 系统目录配置无效');
|
|
151
|
+
const command = win32.join(windows, 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe');
|
|
152
|
+
const encoded = Buffer.from(CODEX_APPX_QUERY, 'utf16le').toString('base64');
|
|
153
|
+
const raw = await capture([command, '-NoLogo', '-NoProfile', '-NonInteractive', '-EncodedCommand', encoded], homedir());
|
|
154
|
+
signal.throwIfAborted();
|
|
155
|
+
return codexAppxExecutable(raw);
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=windows-cli-installation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"windows-cli-installation.js","sourceRoot":"","sources":["../../../src/host/windows-cli-installation.ts"],"names":[],"mappings":"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"}
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { SubprocessHandle, SubprocessSpawnSpec } from '@deepseek-ai/dsh-subprocess';
|
|
2
|
+
import type { ProcessBackend } from './process.ts';
|
|
3
|
+
export declare const isCurrentWindowsRuntime: (value: string) => boolean;
|
|
4
|
+
/** Only console-subsystem targets need a GUI bootstrap. Existing Node helpers
|
|
5
|
+
* already use Electron's GUI executable; terminal allocation stays untouched. */
|
|
6
|
+
export declare function needsWindowsHiddenLaunch(argv: readonly string[], platform: NodeJS.Platform, electron: boolean): boolean;
|
|
7
|
+
/** Window presentation only: all byte streams, collection and process-range
|
|
8
|
+
* ownership remain the SDK's. Native exit facts travel over a private channel,
|
|
9
|
+
* never stdout/stderr and never the native CLI's credential/session protocol. */
|
|
10
|
+
export declare function spawnWindowsHidden(backend: ProcessBackend, spec: SubprocessSpawnSpec, options?: {
|
|
11
|
+
privateUmask?: true;
|
|
12
|
+
}): SubprocessHandle;
|