vigthoria-cli 1.13.26 → 1.13.30
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.md +12 -0
- package/completions/_vigthoria +1 -0
- package/completions/vigthoria.bash +1 -1
- package/completions/vigthoria.fish +1 -0
- package/dist/commands/chat.js +73 -26
- package/dist/commands/config.js +4 -4
- package/dist/commands/creative-registration.d.ts +13 -0
- package/dist/commands/creative-registration.js +88 -0
- package/dist/commands/fork.d.ts +3 -2
- package/dist/commands/fork.js +124 -123
- package/dist/commands/game.d.ts +8 -0
- package/dist/commands/game.js +113 -9
- package/dist/commands/history.d.ts +0 -1
- package/dist/commands/history.js +8 -22
- package/dist/commands/hub.d.ts +20 -0
- package/dist/commands/hub.js +17 -3
- package/dist/commands/preview.js +7 -2
- package/dist/commands/product-run-registration.js +1 -1
- package/dist/commands/replay.d.ts +0 -1
- package/dist/commands/replay.js +10 -19
- package/dist/commands/repo.js +16 -4
- package/dist/commands/update-registration.js +2 -2
- package/dist/commands/workflow.d.ts +4 -0
- package/dist/commands/workflow.js +27 -0
- package/dist/index.js +8 -4
- package/dist/utils/agentRunOutcome.d.ts +7 -0
- package/dist/utils/agentRunOutcome.js +13 -0
- package/dist/utils/api.d.ts +20 -5
- package/dist/utils/api.js +428 -43
- package/dist/utils/command-policy.js +3 -1
- package/dist/utils/config.d.ts +2 -0
- package/dist/utils/config.js +22 -9
- package/dist/utils/frontend-preview-service.d.ts +1 -0
- package/dist/utils/frontend-preview-service.js +54 -5
- package/dist/utils/model-governance.js +23 -14
- package/dist/utils/model-transport-service.js +1 -1
- package/dist/utils/network-policy.js +15 -3
- package/dist/utils/operator-client.js +23 -4
- package/dist/utils/post-write-validator.js +7 -3
- package/dist/utils/preview-screenshot-adapter.d.ts +16 -41
- package/dist/utils/preview-screenshot-adapter.js +273 -64
- package/dist/utils/runtime-capability.d.ts +7 -0
- package/dist/utils/runtime-capability.js +11 -0
- package/dist/utils/runtime-temp.d.ts +5 -2
- package/dist/utils/runtime-temp.js +131 -30
- package/dist/utils/tools.js +1 -1
- package/dist/utils/v3-stream-events.js +10 -2
- package/dist/utils/v3-workspace-service.d.ts +1 -0
- package/dist/utils/v3-workspace-service.js +38 -1
- package/dist/utils/vigflow-client.d.ts +9 -0
- package/dist/utils/vigflow-client.js +48 -2
- package/dist/utils/workspace-reference.d.ts +8 -0
- package/dist/utils/workspace-reference.js +21 -0
- package/install.ps1 +2 -2
- package/install.sh +2 -2
- package/package.json +4 -6
- package/scripts/release/LOCAL_MACHINE_USER_VERIFICATION.md +2 -2
- package/scripts/release/validate-live-service-gates.sh +3 -3
- package/scripts/release/validate-no-go-gates.sh +2 -0
|
@@ -1,103 +1,312 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
2
|
import * as fs from 'node:fs';
|
|
3
3
|
import * as path from 'node:path';
|
|
4
|
-
import {
|
|
4
|
+
import { pathToFileURL } from 'node:url';
|
|
5
|
+
import { redactSensitiveText, safeChildProcessEnv } from './secret-policy.js';
|
|
5
6
|
import { createRuntimeTempDirectory, removeRuntimeTempDirectory } from './runtime-temp.js';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
const SCREENSHOT_WIDTH = 800;
|
|
8
|
+
const SCREENSHOT_HEIGHT = 600;
|
|
9
|
+
const SCREENSHOT_MAX_BYTES = 10 * 1024 * 1024;
|
|
10
|
+
const BROWSER_TIMEOUT_MS = 30_000;
|
|
11
|
+
// Chromium creates short-lived files below TMPDIR while starting. Keep enough
|
|
12
|
+
// room below the 108-byte POSIX sockaddr_un ceiling without rejecting normal
|
|
13
|
+
// per-user Vigthoria roots (for example ~/.vigthoria/tmp/browser-*/scratch).
|
|
14
|
+
const POSIX_BROWSER_SCRATCH_MAX_BYTES = 76;
|
|
15
|
+
export function resolvePreviewBrowserExecutable(environment = process.env, platform = process.platform, exists = fs.existsSync) {
|
|
16
|
+
const candidates = platform === 'win32'
|
|
17
|
+
? [
|
|
18
|
+
...[environment['PROGRAMFILES(X86)'], environment.ProgramFiles, environment.LOCALAPPDATA]
|
|
19
|
+
.filter((value) => typeof value === 'string' && value.length > 0)
|
|
20
|
+
.flatMap((base) => [
|
|
21
|
+
path.win32.join(base, 'Microsoft', 'Edge', 'Application', 'msedge.exe'),
|
|
22
|
+
path.win32.join(base, 'Google', 'Chrome', 'Application', 'chrome.exe'),
|
|
23
|
+
]),
|
|
24
|
+
]
|
|
25
|
+
: platform === 'darwin'
|
|
26
|
+
? [
|
|
27
|
+
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
|
|
28
|
+
'/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge',
|
|
29
|
+
'/Applications/Chromium.app/Contents/MacOS/Chromium',
|
|
30
|
+
]
|
|
31
|
+
: [
|
|
32
|
+
'/usr/bin/google-chrome',
|
|
33
|
+
'/usr/bin/google-chrome-stable',
|
|
34
|
+
'/usr/bin/microsoft-edge',
|
|
35
|
+
'/usr/bin/microsoft-edge-stable',
|
|
36
|
+
'/usr/bin/chromium',
|
|
37
|
+
'/usr/bin/chromium-browser',
|
|
38
|
+
'/snap/bin/chromium',
|
|
39
|
+
];
|
|
40
|
+
for (const candidate of candidates) {
|
|
41
|
+
if (exists(candidate))
|
|
42
|
+
return { executablePath: candidate, source: 'system' };
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
async function terminateBrowserProcess(child, platform) {
|
|
47
|
+
const pid = child.pid;
|
|
48
|
+
if (!pid)
|
|
49
|
+
return;
|
|
50
|
+
if (platform === 'win32') {
|
|
51
|
+
const taskkill = path.win32.join(process.env.SystemRoot || 'C:\\Windows', 'System32', 'taskkill.exe');
|
|
52
|
+
await new Promise((resolve) => {
|
|
53
|
+
const killer = spawn(taskkill, ['/PID', String(pid), '/T', '/F'], {
|
|
54
|
+
stdio: 'ignore', windowsHide: true, env: safeChildProcessEnv(),
|
|
55
|
+
});
|
|
56
|
+
const timer = setTimeout(() => {
|
|
57
|
+
try {
|
|
58
|
+
killer.kill();
|
|
59
|
+
}
|
|
60
|
+
catch { /* helper already exited */ }
|
|
61
|
+
try {
|
|
62
|
+
child.kill();
|
|
63
|
+
}
|
|
64
|
+
catch { /* exact child already exited */ }
|
|
65
|
+
resolve();
|
|
66
|
+
}, 5_000);
|
|
67
|
+
killer.once('error', () => { clearTimeout(timer); try {
|
|
68
|
+
child.kill();
|
|
69
|
+
}
|
|
70
|
+
catch { /* exact child only */ } resolve(); });
|
|
71
|
+
killer.once('exit', () => { clearTimeout(timer); resolve(); });
|
|
72
|
+
});
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
9
75
|
try {
|
|
10
|
-
|
|
11
|
-
if (packaged && exists(packaged))
|
|
12
|
-
return { executablePath: packaged, headless: 'shell', source: 'packaged' };
|
|
76
|
+
process.kill(-pid, 'SIGTERM');
|
|
13
77
|
}
|
|
14
78
|
catch {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if (platform !== 'win32')
|
|
18
|
-
return null;
|
|
19
|
-
const bases = [environment['PROGRAMFILES(X86)'], environment.ProgramFiles, environment.LOCALAPPDATA]
|
|
20
|
-
.filter((value) => typeof value === 'string' && value.length > 0);
|
|
21
|
-
const relatives = [
|
|
22
|
-
['Microsoft', 'Edge', 'Application', 'msedge.exe'],
|
|
23
|
-
['Google', 'Chrome', 'Application', 'chrome.exe'],
|
|
24
|
-
];
|
|
25
|
-
for (const base of bases) {
|
|
26
|
-
for (const relative of relatives) {
|
|
27
|
-
const candidate = path.win32.join(base, ...relative);
|
|
28
|
-
if (exists(candidate))
|
|
29
|
-
return { executablePath: candidate, headless: true, source: 'system' };
|
|
79
|
+
try {
|
|
80
|
+
child.kill('SIGTERM');
|
|
30
81
|
}
|
|
82
|
+
catch { /* already gone */ }
|
|
31
83
|
}
|
|
32
|
-
|
|
84
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
85
|
+
try {
|
|
86
|
+
process.kill(-pid, 0);
|
|
87
|
+
process.kill(-pid, 'SIGKILL');
|
|
88
|
+
}
|
|
89
|
+
catch { /* group exited */ }
|
|
33
90
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
91
|
+
export const runPreviewBrowser = (executablePath, args, platform, environment = process.env) => new Promise((resolve, reject) => {
|
|
92
|
+
const child = spawn(executablePath, [...args], {
|
|
93
|
+
stdio: 'ignore',
|
|
94
|
+
windowsHide: true,
|
|
95
|
+
env: safeChildProcessEnv(environment),
|
|
96
|
+
detached: platform !== 'win32',
|
|
97
|
+
});
|
|
98
|
+
let settled = false;
|
|
99
|
+
const finish = (error) => {
|
|
100
|
+
if (settled)
|
|
101
|
+
return;
|
|
102
|
+
settled = true;
|
|
103
|
+
clearTimeout(timer);
|
|
104
|
+
error ? reject(error) : resolve();
|
|
105
|
+
};
|
|
106
|
+
const timer = setTimeout(() => {
|
|
107
|
+
void terminateBrowserProcess(child, platform).finally(() => finish(new Error(`browser screenshot timed out after ${BROWSER_TIMEOUT_MS}ms`)));
|
|
108
|
+
}, BROWSER_TIMEOUT_MS);
|
|
109
|
+
child.once('error', (error) => finish(error));
|
|
110
|
+
child.once('exit', (code, signal) => {
|
|
111
|
+
if (code === 0)
|
|
112
|
+
finish();
|
|
113
|
+
else
|
|
114
|
+
finish(new Error(`browser screenshot process exited with ${signal || code}`));
|
|
38
115
|
});
|
|
116
|
+
});
|
|
117
|
+
function pngCrc32(data) {
|
|
118
|
+
let crc = 0xffffffff;
|
|
119
|
+
for (const byte of data) {
|
|
120
|
+
crc ^= byte;
|
|
121
|
+
for (let bit = 0; bit < 8; bit += 1) {
|
|
122
|
+
crc = (crc >>> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return (crc ^ 0xffffffff) >>> 0;
|
|
126
|
+
}
|
|
127
|
+
function validatePng(filePath) {
|
|
128
|
+
const stat = fs.statSync(filePath);
|
|
129
|
+
if (!stat.isFile() || stat.size < 57 || stat.size > SCREENSHOT_MAX_BYTES) {
|
|
130
|
+
throw new Error('browser did not produce a bounded PNG screenshot');
|
|
131
|
+
}
|
|
132
|
+
const bytes = fs.readFileSync(filePath);
|
|
133
|
+
if (!bytes.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))) {
|
|
134
|
+
throw new Error('browser screenshot output is not a PNG file');
|
|
135
|
+
}
|
|
136
|
+
let offset = 8;
|
|
137
|
+
let chunks = 0;
|
|
138
|
+
let sawHeader = false;
|
|
139
|
+
let sawImageData = false;
|
|
140
|
+
let sawEnd = false;
|
|
141
|
+
while (offset + 12 <= bytes.length && chunks < 4096) {
|
|
142
|
+
const length = bytes.readUInt32BE(offset);
|
|
143
|
+
const chunkEnd = offset + 12 + length;
|
|
144
|
+
if (chunkEnd > bytes.length)
|
|
145
|
+
throw new Error('browser screenshot PNG contains a truncated chunk');
|
|
146
|
+
const typeBytes = bytes.subarray(offset + 4, offset + 8);
|
|
147
|
+
const type = typeBytes.toString('ascii');
|
|
148
|
+
const data = bytes.subarray(offset + 8, offset + 8 + length);
|
|
149
|
+
const expectedCrc = bytes.readUInt32BE(offset + 8 + length);
|
|
150
|
+
if (pngCrc32(Buffer.concat([typeBytes, data])) !== expectedCrc) {
|
|
151
|
+
throw new Error('browser screenshot PNG contains an invalid chunk checksum');
|
|
152
|
+
}
|
|
153
|
+
chunks += 1;
|
|
154
|
+
if (chunks === 1 && (type !== 'IHDR' || length !== 13)) {
|
|
155
|
+
throw new Error('browser screenshot PNG has no valid leading IHDR chunk');
|
|
156
|
+
}
|
|
157
|
+
if (type === 'IHDR') {
|
|
158
|
+
if (sawHeader || length !== 13)
|
|
159
|
+
throw new Error('browser screenshot PNG has an invalid IHDR chunk');
|
|
160
|
+
sawHeader = true;
|
|
161
|
+
const width = data.readUInt32BE(0);
|
|
162
|
+
const height = data.readUInt32BE(4);
|
|
163
|
+
if (width !== SCREENSHOT_WIDTH || height !== SCREENSHOT_HEIGHT) {
|
|
164
|
+
throw new Error(`browser screenshot dimensions were ${width}x${height}; expected ${SCREENSHOT_WIDTH}x${SCREENSHOT_HEIGHT}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
else if (type === 'IDAT') {
|
|
168
|
+
if (!sawHeader || length === 0)
|
|
169
|
+
throw new Error('browser screenshot PNG has invalid image data');
|
|
170
|
+
sawImageData = true;
|
|
171
|
+
}
|
|
172
|
+
else if (type === 'IEND') {
|
|
173
|
+
if (length !== 0 || !sawImageData)
|
|
174
|
+
throw new Error('browser screenshot PNG has an invalid IEND chunk');
|
|
175
|
+
sawEnd = true;
|
|
176
|
+
offset = chunkEnd;
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
offset = chunkEnd;
|
|
180
|
+
}
|
|
181
|
+
if (!sawHeader || !sawImageData || !sawEnd || offset !== bytes.length) {
|
|
182
|
+
throw new Error('browser screenshot PNG is incomplete or contains trailing data');
|
|
183
|
+
}
|
|
39
184
|
}
|
|
40
|
-
|
|
41
|
-
|
|
185
|
+
function isTransientBrowserFailure(result) {
|
|
186
|
+
if (result.captured || !result.error || /profile cleanup failed/i.test(result.error))
|
|
187
|
+
return false;
|
|
188
|
+
return /(?:process exited with (?:SIG[A-Z]+|[1-9][0-9]*)|timed out|\bE(?:ACCES|PERM|BUSY|AGAIN)\b|resource temporarily unavailable)/i.test(result.error);
|
|
189
|
+
}
|
|
190
|
+
/** Dependency-free system-browser adapter. No browser download or archive
|
|
191
|
+
* extractor is shipped, and only fixed operating-system installation paths
|
|
192
|
+
* are eligible.
|
|
193
|
+
*/
|
|
194
|
+
export class SystemBrowserScreenshotAdapter {
|
|
42
195
|
environment;
|
|
43
196
|
allocateTemp;
|
|
44
197
|
releaseTemp;
|
|
45
198
|
platform;
|
|
46
|
-
|
|
47
|
-
|
|
199
|
+
exists;
|
|
200
|
+
runner;
|
|
201
|
+
constructor(environment = process.env, allocateTemp = createRuntimeTempDirectory, releaseTemp = removeRuntimeTempDirectory, platform = process.platform, exists = fs.existsSync, runner = runPreviewBrowser) {
|
|
48
202
|
this.environment = environment;
|
|
49
203
|
this.allocateTemp = allocateTemp;
|
|
50
204
|
this.releaseTemp = releaseTemp;
|
|
51
205
|
this.platform = platform;
|
|
206
|
+
this.exists = exists;
|
|
207
|
+
this.runner = runner;
|
|
52
208
|
}
|
|
53
209
|
async capture(entryAbsolutePath, screenshotPath) {
|
|
54
210
|
if (this.environment.VIGTHORIA_DISABLE_PREVIEW_SCREENSHOT === '1') {
|
|
55
211
|
return { captured: false, error: 'screenshot capture explicitly unavailable' };
|
|
56
212
|
}
|
|
213
|
+
const resolution = resolvePreviewBrowserExecutable(this.environment, this.platform, this.exists);
|
|
214
|
+
if (!resolution) {
|
|
215
|
+
return { captured: false, error: 'required system browser is unavailable; install Microsoft Edge, Chrome, or Chromium' };
|
|
216
|
+
}
|
|
217
|
+
// Headless Chromium-family processes can fail transiently while a previous
|
|
218
|
+
// profile/process is releasing OS resources. Screenshot generation is a
|
|
219
|
+
// local idempotent operation, so one fresh-profile retry is safe. Invalid
|
|
220
|
+
// proof bytes and cleanup failures are never retried or credited.
|
|
221
|
+
let lastResult = { captured: false, error: 'browser screenshot was not attempted' };
|
|
222
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
223
|
+
lastResult = await this.captureOnce(resolution, entryAbsolutePath, screenshotPath);
|
|
224
|
+
if (lastResult.captured || !isTransientBrowserFailure(lastResult))
|
|
225
|
+
return lastResult;
|
|
226
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
227
|
+
}
|
|
228
|
+
return lastResult;
|
|
229
|
+
}
|
|
230
|
+
async captureOnce(resolution, entryAbsolutePath, screenshotPath) {
|
|
231
|
+
let browserProfile = null;
|
|
232
|
+
let result;
|
|
57
233
|
try {
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
234
|
+
browserProfile = this.allocateTemp('browser-', 128 * 1024 * 1024);
|
|
235
|
+
const browserUserData = path.join(browserProfile, 'profile');
|
|
236
|
+
const browserScratch = path.join(browserProfile, 'scratch');
|
|
237
|
+
if (this.platform !== 'win32' && Buffer.byteLength(browserScratch) > POSIX_BROWSER_SCRATCH_MAX_BYTES) {
|
|
238
|
+
throw new Error('managed browser temporary path is too long; configure a shorter dedicated VIGTHORIA_TEMP_DIR');
|
|
62
239
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
240
|
+
fs.mkdirSync(browserUserData, { recursive: false, mode: 0o700 });
|
|
241
|
+
fs.mkdirSync(browserScratch, { recursive: false, mode: 0o700 });
|
|
242
|
+
fs.mkdirSync(path.dirname(screenshotPath), { recursive: true, mode: 0o700 });
|
|
243
|
+
try {
|
|
244
|
+
fs.unlinkSync(screenshotPath);
|
|
66
245
|
}
|
|
67
|
-
|
|
68
|
-
|
|
246
|
+
catch (error) {
|
|
247
|
+
if (error?.code !== 'ENOENT')
|
|
248
|
+
throw error;
|
|
249
|
+
}
|
|
250
|
+
const args = [
|
|
251
|
+
'--headless=new',
|
|
252
|
+
'--disable-gpu',
|
|
253
|
+
'--disable-dev-shm-usage',
|
|
254
|
+
'--hide-scrollbars',
|
|
255
|
+
'--no-first-run',
|
|
256
|
+
'--no-default-browser-check',
|
|
257
|
+
'--disable-background-networking',
|
|
258
|
+
'--disable-component-update',
|
|
259
|
+
'--disable-sync',
|
|
260
|
+
'--metrics-recording-only',
|
|
261
|
+
'--proxy-server=http://127.0.0.1:9',
|
|
262
|
+
'--proxy-bypass-list=<-loopback>',
|
|
263
|
+
`--user-data-dir=${browserUserData}`,
|
|
264
|
+
`--window-size=${SCREENSHOT_WIDTH},${SCREENSHOT_HEIGHT}`,
|
|
265
|
+
`--screenshot=${screenshotPath}`,
|
|
266
|
+
'--allow-file-access-from-files',
|
|
267
|
+
pathToFileURL(entryAbsolutePath).toString(),
|
|
268
|
+
];
|
|
269
|
+
const browserEnvironment = safeChildProcessEnv(this.environment, {
|
|
270
|
+
TMPDIR: browserScratch,
|
|
271
|
+
TMP: browserScratch,
|
|
272
|
+
TEMP: browserScratch,
|
|
273
|
+
});
|
|
274
|
+
await this.runner(resolution.executablePath, args, this.platform, browserEnvironment);
|
|
275
|
+
validatePng(screenshotPath);
|
|
276
|
+
result = { captured: true };
|
|
277
|
+
}
|
|
278
|
+
catch (error) {
|
|
69
279
|
try {
|
|
70
|
-
|
|
71
|
-
headless: browserResolution.headless,
|
|
72
|
-
args: ['--no-sandbox', '--disable-setuid-sandbox'],
|
|
73
|
-
userDataDir: browserProfile,
|
|
74
|
-
executablePath: browserResolution.executablePath,
|
|
75
|
-
timeout: 20_000,
|
|
76
|
-
protocolTimeout: 20_000,
|
|
77
|
-
}), 25_000, 'browser launch');
|
|
78
|
-
const page = await withTimeout(browser.newPage(), 10_000, 'browser page creation');
|
|
79
|
-
await withTimeout(page.setViewport({ width: 800, height: 600, deviceScaleFactor: 1 }), 10_000, 'browser viewport setup');
|
|
80
|
-
await page.goto(pathToFileURL(entryAbsolutePath).toString(), { waitUntil: 'networkidle0', timeout: 20_000 });
|
|
81
|
-
await withTimeout(page.screenshot({ path: screenshotPath, fullPage: false }), 20_000, 'screenshot capture');
|
|
280
|
+
fs.unlinkSync(screenshotPath);
|
|
82
281
|
}
|
|
83
|
-
|
|
84
|
-
|
|
282
|
+
catch { /* no failed proof artifact */ }
|
|
283
|
+
result = { captured: false, error: redactSensitiveText(error instanceof Error ? error.message : String(error)) };
|
|
284
|
+
}
|
|
285
|
+
finally {
|
|
286
|
+
if (browserProfile) {
|
|
287
|
+
try {
|
|
288
|
+
this.releaseTemp(browserProfile);
|
|
289
|
+
}
|
|
290
|
+
catch {
|
|
291
|
+
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
85
292
|
try {
|
|
86
|
-
|
|
293
|
+
this.releaseTemp(browserProfile);
|
|
87
294
|
}
|
|
88
|
-
catch {
|
|
295
|
+
catch (cleanupError) {
|
|
89
296
|
try {
|
|
90
|
-
|
|
297
|
+
fs.unlinkSync(screenshotPath);
|
|
91
298
|
}
|
|
92
|
-
catch { /*
|
|
299
|
+
catch { /* proof is invalid when cleanup is incomplete */ }
|
|
300
|
+
result = {
|
|
301
|
+
captured: false,
|
|
302
|
+
error: redactSensitiveText(`browser profile cleanup failed: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`),
|
|
303
|
+
};
|
|
93
304
|
}
|
|
94
305
|
}
|
|
95
|
-
this.releaseTemp(browserProfile);
|
|
96
306
|
}
|
|
97
|
-
return { captured: true };
|
|
98
|
-
}
|
|
99
|
-
catch (error) {
|
|
100
|
-
return { captured: false, error: redactSensitiveText(error instanceof Error ? error.message : String(error)) };
|
|
101
307
|
}
|
|
308
|
+
return result;
|
|
102
309
|
}
|
|
103
310
|
}
|
|
311
|
+
/** @deprecated Internal compatibility alias retained for older deep imports. */
|
|
312
|
+
export { SystemBrowserScreenshotAdapter as OptionalPuppeteerScreenshotAdapter };
|
|
@@ -6,3 +6,10 @@ export type RuntimeCapabilities = {
|
|
|
6
6
|
export declare function resolveRuntimeCapabilities(environment?: NodeJS.ProcessEnv): RuntimeCapabilities;
|
|
7
7
|
export declare function hasLoopbackServiceCapability(environment?: NodeJS.ProcessEnv): boolean;
|
|
8
8
|
export declare function hasLocalV3AgentCapability(environment?: NodeJS.ProcessEnv): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* An internal V3 service key may replace a user session only for an Agent
|
|
11
|
+
* request deliberately pinned to the local V3 service. Requiring both grants
|
|
12
|
+
* prevents a key present on an ecosystem host from bypassing unrelated
|
|
13
|
+
* user-session policies.
|
|
14
|
+
*/
|
|
15
|
+
export declare function hasLocalV3ServiceIdentity(environment?: NodeJS.ProcessEnv): boolean;
|
|
@@ -14,3 +14,14 @@ export function hasLoopbackServiceCapability(environment = process.env) {
|
|
|
14
14
|
export function hasLocalV3AgentCapability(environment = process.env) {
|
|
15
15
|
return resolveRuntimeCapabilities(environment).localV3Agent;
|
|
16
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* An internal V3 service key may replace a user session only for an Agent
|
|
19
|
+
* request deliberately pinned to the local V3 service. Requiring both grants
|
|
20
|
+
* prevents a key present on an ecosystem host from bypassing unrelated
|
|
21
|
+
* user-session policies.
|
|
22
|
+
*/
|
|
23
|
+
export function hasLocalV3ServiceIdentity(environment = process.env) {
|
|
24
|
+
return hasLocalV3AgentCapability(environment) && Boolean(environment.VIGTHORIA_V3_SERVICE_KEY
|
|
25
|
+
|| environment.V3_SERVICE_KEY
|
|
26
|
+
|| environment.HYPERLOOP_SERVICE_KEY);
|
|
27
|
+
}
|
|
@@ -49,6 +49,7 @@ export declare class RuntimeTempManager {
|
|
|
49
49
|
private readonly source;
|
|
50
50
|
private readonly maxBytes;
|
|
51
51
|
private readonly minimumFreeBytes;
|
|
52
|
+
private readonly allocationMaxBytes;
|
|
52
53
|
private readonly ttlMs;
|
|
53
54
|
private initializedRoot;
|
|
54
55
|
private initializedIdentity;
|
|
@@ -56,7 +57,7 @@ export declare class RuntimeTempManager {
|
|
|
56
57
|
private lastCleanup;
|
|
57
58
|
constructor(options?: RuntimeTempOptions);
|
|
58
59
|
initialize(): RuntimeTempStatus;
|
|
59
|
-
createDirectory(prefix?: string): string;
|
|
60
|
+
createDirectory(prefix?: string, requestedMaxBytes?: number): string;
|
|
60
61
|
removeDirectory(directory: string): void;
|
|
61
62
|
scavenge(options?: {
|
|
62
63
|
includeLegacy?: boolean;
|
|
@@ -68,10 +69,12 @@ export declare class RuntimeTempManager {
|
|
|
68
69
|
private freeBytes;
|
|
69
70
|
private measure;
|
|
70
71
|
private removeEntry;
|
|
72
|
+
private acquireLock;
|
|
73
|
+
private releaseLock;
|
|
71
74
|
private cleanupLegacySystemTemp;
|
|
72
75
|
}
|
|
73
76
|
export declare function getRuntimeTempManager(): RuntimeTempManager;
|
|
74
77
|
export declare function initializeRuntimeTempStorage(): RuntimeTempStatus;
|
|
75
78
|
export declare function runtimeTempStatus(): RuntimeTempStatus;
|
|
76
|
-
export declare function createRuntimeTempDirectory(prefix: string): string;
|
|
79
|
+
export declare function createRuntimeTempDirectory(prefix: string, requestedMaxBytes?: number): string;
|
|
77
80
|
export declare function removeRuntimeTempDirectory(directory: string): void;
|