@steipete/oracle 0.8.5 → 0.8.6
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 +23 -1
- package/dist/bin/oracle-cli.js +189 -7
- package/dist/src/browser/actions/assistantResponse.js +72 -37
- package/dist/src/browser/actions/promptComposer.js +141 -32
- package/dist/src/browser/chromeLifecycle.js +25 -9
- package/dist/src/browser/config.js +14 -0
- package/dist/src/browser/index.js +341 -24
- package/dist/src/browser/profileState.js +93 -0
- package/dist/src/cli/browserConfig.js +21 -0
- package/dist/src/cli/browserDefaults.js +21 -0
- package/dist/src/cli/sessionRunner.js +149 -0
- package/dist/src/cli/tui/index.js +1 -0
- package/dist/src/mcp/tools/consult.js +1 -0
- package/dist/src/oracle/modelResolver.js +33 -1
- package/dist/src/sessionManager.js +9 -2
- package/dist/src/sessionStore.js +2 -2
- package/dist/vendor/oracle-notifier/OracleNotifier.app/Contents/CodeResources +0 -0
- package/dist/vendor/oracle-notifier/OracleNotifier.app/Contents/MacOS/OracleNotifier +0 -0
- package/package.json +19 -19
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/CodeResources +0 -0
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/MacOS/OracleNotifier +0 -0
|
@@ -18,6 +18,13 @@ export async function submitPrompt(deps, prompt, logger) {
|
|
|
18
18
|
expression: `(() => {
|
|
19
19
|
${buildClickDispatcher()}
|
|
20
20
|
const SELECTORS = ${JSON.stringify(INPUT_SELECTORS)};
|
|
21
|
+
const isVisible = (node) => {
|
|
22
|
+
if (!node || typeof node.getBoundingClientRect !== 'function') {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
const rect = node.getBoundingClientRect();
|
|
26
|
+
return rect.width > 0 && rect.height > 0;
|
|
27
|
+
};
|
|
21
28
|
const focusNode = (node) => {
|
|
22
29
|
if (!node) {
|
|
23
30
|
return false;
|
|
@@ -39,13 +46,17 @@ export async function submitPrompt(deps, prompt, logger) {
|
|
|
39
46
|
return true;
|
|
40
47
|
};
|
|
41
48
|
|
|
49
|
+
const candidates = [];
|
|
42
50
|
for (const selector of SELECTORS) {
|
|
43
51
|
const node = document.querySelector(selector);
|
|
44
|
-
if (
|
|
45
|
-
|
|
46
|
-
return { focused: true };
|
|
52
|
+
if (node) {
|
|
53
|
+
candidates.push(node);
|
|
47
54
|
}
|
|
48
55
|
}
|
|
56
|
+
const preferred = candidates.find((node) => isVisible(node)) || candidates[0];
|
|
57
|
+
if (preferred && focusNode(preferred)) {
|
|
58
|
+
return { focused: true };
|
|
59
|
+
}
|
|
49
60
|
return { focused: false };
|
|
50
61
|
})()`,
|
|
51
62
|
returnByValue: true,
|
|
@@ -65,18 +76,36 @@ export async function submitPrompt(deps, prompt, logger) {
|
|
|
65
76
|
expression: `(() => {
|
|
66
77
|
const editor = document.querySelector(${primarySelectorLiteral});
|
|
67
78
|
const fallback = document.querySelector(${fallbackSelectorLiteral});
|
|
79
|
+
const inputSelectors = ${JSON.stringify(INPUT_SELECTORS)};
|
|
80
|
+
const readValue = (node) => {
|
|
81
|
+
if (!node) return '';
|
|
82
|
+
if (node instanceof HTMLTextAreaElement) return node.value ?? '';
|
|
83
|
+
return node.innerText ?? '';
|
|
84
|
+
};
|
|
85
|
+
const isVisible = (node) => {
|
|
86
|
+
if (!node || typeof node.getBoundingClientRect !== 'function') return false;
|
|
87
|
+
const rect = node.getBoundingClientRect();
|
|
88
|
+
return rect.width > 0 && rect.height > 0;
|
|
89
|
+
};
|
|
90
|
+
const candidates = inputSelectors
|
|
91
|
+
.map((selector) => document.querySelector(selector))
|
|
92
|
+
.filter((node) => Boolean(node));
|
|
93
|
+
const active = candidates.find((node) => isVisible(node)) || candidates[0] || null;
|
|
68
94
|
return {
|
|
69
95
|
editorText: editor?.innerText ?? '',
|
|
70
96
|
fallbackValue: fallback?.value ?? '',
|
|
97
|
+
activeValue: active ? readValue(active) : '',
|
|
71
98
|
};
|
|
72
99
|
})()`,
|
|
73
100
|
returnByValue: true,
|
|
74
101
|
});
|
|
75
102
|
const editorTextRaw = verification.result?.value?.editorText ?? '';
|
|
76
103
|
const fallbackValueRaw = verification.result?.value?.fallbackValue ?? '';
|
|
104
|
+
const activeValueRaw = verification.result?.value?.activeValue ?? '';
|
|
77
105
|
const editorTextTrimmed = editorTextRaw?.trim?.() ?? '';
|
|
78
106
|
const fallbackValueTrimmed = fallbackValueRaw?.trim?.() ?? '';
|
|
79
|
-
|
|
107
|
+
const activeValueTrimmed = activeValueRaw?.trim?.() ?? '';
|
|
108
|
+
if (!editorTextTrimmed && !fallbackValueTrimmed && !activeValueTrimmed) {
|
|
80
109
|
// Learned: occasionally Input.insertText doesn't land in the editor; force textContent/value + input events.
|
|
81
110
|
await runtime.evaluate({
|
|
82
111
|
expression: `(() => {
|
|
@@ -100,16 +129,33 @@ export async function submitPrompt(deps, prompt, logger) {
|
|
|
100
129
|
expression: `(() => {
|
|
101
130
|
const editor = document.querySelector(${primarySelectorLiteral});
|
|
102
131
|
const fallback = document.querySelector(${fallbackSelectorLiteral});
|
|
132
|
+
const inputSelectors = ${JSON.stringify(INPUT_SELECTORS)};
|
|
133
|
+
const readValue = (node) => {
|
|
134
|
+
if (!node) return '';
|
|
135
|
+
if (node instanceof HTMLTextAreaElement) return node.value ?? '';
|
|
136
|
+
return node.innerText ?? '';
|
|
137
|
+
};
|
|
138
|
+
const isVisible = (node) => {
|
|
139
|
+
if (!node || typeof node.getBoundingClientRect !== 'function') return false;
|
|
140
|
+
const rect = node.getBoundingClientRect();
|
|
141
|
+
return rect.width > 0 && rect.height > 0;
|
|
142
|
+
};
|
|
143
|
+
const candidates = inputSelectors
|
|
144
|
+
.map((selector) => document.querySelector(selector))
|
|
145
|
+
.filter((node) => Boolean(node));
|
|
146
|
+
const active = candidates.find((node) => isVisible(node)) || candidates[0] || null;
|
|
103
147
|
return {
|
|
104
148
|
editorText: editor?.innerText ?? '',
|
|
105
149
|
fallbackValue: fallback?.value ?? '',
|
|
150
|
+
activeValue: active ? readValue(active) : '',
|
|
106
151
|
};
|
|
107
152
|
})()`,
|
|
108
153
|
returnByValue: true,
|
|
109
154
|
});
|
|
110
155
|
const observedEditor = postVerification.result?.value?.editorText ?? '';
|
|
111
156
|
const observedFallback = postVerification.result?.value?.fallbackValue ?? '';
|
|
112
|
-
const
|
|
157
|
+
const observedActive = postVerification.result?.value?.activeValue ?? '';
|
|
158
|
+
const observedLength = Math.max(observedEditor.length, observedFallback.length, observedActive.length);
|
|
113
159
|
if (promptLength >= 50_000 && observedLength > 0 && observedLength < promptLength - 2_000) {
|
|
114
160
|
// Learned: very large prompts can truncate silently; fail fast so we can fall back to file uploads.
|
|
115
161
|
await logDomFailure(runtime, logger, 'prompt-too-large');
|
|
@@ -144,10 +190,12 @@ export async function submitPrompt(deps, prompt, logger) {
|
|
|
144
190
|
export async function clearPromptComposer(Runtime, logger) {
|
|
145
191
|
const primarySelectorLiteral = JSON.stringify(PROMPT_PRIMARY_SELECTOR);
|
|
146
192
|
const fallbackSelectorLiteral = JSON.stringify(PROMPT_FALLBACK_SELECTOR);
|
|
193
|
+
const inputSelectorsLiteral = JSON.stringify(INPUT_SELECTORS);
|
|
147
194
|
const result = await Runtime.evaluate({
|
|
148
195
|
expression: `(() => {
|
|
149
196
|
const fallback = document.querySelector(${fallbackSelectorLiteral});
|
|
150
197
|
const editor = document.querySelector(${primarySelectorLiteral});
|
|
198
|
+
const inputSelectors = ${inputSelectorsLiteral};
|
|
151
199
|
let cleared = false;
|
|
152
200
|
if (fallback) {
|
|
153
201
|
fallback.value = '';
|
|
@@ -160,6 +208,24 @@ export async function clearPromptComposer(Runtime, logger) {
|
|
|
160
208
|
editor.dispatchEvent(new InputEvent('input', { bubbles: true, data: '', inputType: 'deleteByCut' }));
|
|
161
209
|
cleared = true;
|
|
162
210
|
}
|
|
211
|
+
const nodes = inputSelectors
|
|
212
|
+
.map((selector) => document.querySelector(selector))
|
|
213
|
+
.filter((node) => Boolean(node));
|
|
214
|
+
for (const node of nodes) {
|
|
215
|
+
if (!node) continue;
|
|
216
|
+
if (node instanceof HTMLTextAreaElement) {
|
|
217
|
+
node.value = '';
|
|
218
|
+
node.dispatchEvent(new InputEvent('input', { bubbles: true, data: '', inputType: 'deleteByCut' }));
|
|
219
|
+
node.dispatchEvent(new Event('change', { bubbles: true }));
|
|
220
|
+
cleared = true;
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
if (node.isContentEditable || node.getAttribute('contenteditable') === 'true') {
|
|
224
|
+
node.textContent = '';
|
|
225
|
+
node.dispatchEvent(new InputEvent('input', { bubbles: true, data: '', inputType: 'deleteByCut' }));
|
|
226
|
+
cleared = true;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
163
229
|
return { cleared };
|
|
164
230
|
})()`,
|
|
165
231
|
returnByValue: true,
|
|
@@ -281,15 +347,34 @@ async function verifyPromptCommitted(Runtime, prompt, timeoutMs, logger, baselin
|
|
|
281
347
|
const encodedPrompt = JSON.stringify(prompt.trim());
|
|
282
348
|
const primarySelectorLiteral = JSON.stringify(PROMPT_PRIMARY_SELECTOR);
|
|
283
349
|
const fallbackSelectorLiteral = JSON.stringify(PROMPT_FALLBACK_SELECTOR);
|
|
350
|
+
const inputSelectorsLiteral = JSON.stringify(INPUT_SELECTORS);
|
|
284
351
|
const stopSelectorLiteral = JSON.stringify(STOP_BUTTON_SELECTOR);
|
|
285
352
|
const assistantSelectorLiteral = JSON.stringify(ASSISTANT_ROLE_SELECTOR);
|
|
286
|
-
const
|
|
353
|
+
const turnSelectorLiteral = JSON.stringify(CONVERSATION_TURN_SELECTOR);
|
|
354
|
+
let baseline = typeof baselineTurns === 'number' && Number.isFinite(baselineTurns) && baselineTurns >= 0
|
|
287
355
|
? Math.floor(baselineTurns)
|
|
288
|
-
:
|
|
356
|
+
: null;
|
|
357
|
+
if (baseline === null) {
|
|
358
|
+
try {
|
|
359
|
+
const { result } = await Runtime.evaluate({
|
|
360
|
+
expression: `document.querySelectorAll(${turnSelectorLiteral}).length`,
|
|
361
|
+
returnByValue: true,
|
|
362
|
+
});
|
|
363
|
+
const raw = typeof result?.value === 'number' ? result.value : Number(result?.value);
|
|
364
|
+
if (Number.isFinite(raw)) {
|
|
365
|
+
baseline = Math.max(0, Math.floor(raw));
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
catch {
|
|
369
|
+
// ignore; baseline stays unknown
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
const baselineLiteral = baseline ?? -1;
|
|
289
373
|
// Learned: ChatGPT can echo/format text; normalize markdown and use prefix matches to detect the sent prompt.
|
|
290
374
|
const script = `(() => {
|
|
291
|
-
|
|
292
|
-
|
|
375
|
+
const editor = document.querySelector(${primarySelectorLiteral});
|
|
376
|
+
const fallback = document.querySelector(${fallbackSelectorLiteral});
|
|
377
|
+
const inputSelectors = ${inputSelectorsLiteral};
|
|
293
378
|
const normalize = (value) => {
|
|
294
379
|
let text = value?.toLowerCase?.() ?? '';
|
|
295
380
|
// Strip markdown *markers* but keep content (ChatGPT renders fence markers differently).
|
|
@@ -303,35 +388,53 @@ async function verifyPromptCommitted(Runtime, prompt, timeoutMs, logger, baselin
|
|
|
303
388
|
const CONVERSATION_SELECTOR = ${JSON.stringify(CONVERSATION_TURN_SELECTOR)};
|
|
304
389
|
const articles = Array.from(document.querySelectorAll(CONVERSATION_SELECTOR));
|
|
305
390
|
const normalizedTurns = articles.map((node) => normalize(node?.innerText));
|
|
391
|
+
const readValue = (node) => {
|
|
392
|
+
if (!node) return '';
|
|
393
|
+
if (node instanceof HTMLTextAreaElement) return node.value ?? '';
|
|
394
|
+
return node.innerText ?? '';
|
|
395
|
+
};
|
|
396
|
+
const isVisible = (node) => {
|
|
397
|
+
if (!node || typeof node.getBoundingClientRect !== 'function') return false;
|
|
398
|
+
const rect = node.getBoundingClientRect();
|
|
399
|
+
return rect.width > 0 && rect.height > 0;
|
|
400
|
+
};
|
|
401
|
+
const inputs = inputSelectors
|
|
402
|
+
.map((selector) => document.querySelector(selector))
|
|
403
|
+
.filter((node) => Boolean(node));
|
|
404
|
+
const visibleInputs = inputs.filter((node) => isVisible(node));
|
|
405
|
+
const activeInputs = visibleInputs.length > 0 ? visibleInputs : inputs;
|
|
306
406
|
const userMatched =
|
|
307
407
|
normalizedPrompt.length > 0 && normalizedTurns.some((text) => text.includes(normalizedPrompt));
|
|
308
408
|
const prefixMatched =
|
|
309
409
|
normalizedPromptPrefix.length > 30 &&
|
|
310
410
|
normalizedTurns.some((text) => text.includes(normalizedPromptPrefix));
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
411
|
+
const lastTurn = normalizedTurns[normalizedTurns.length - 1] ?? '';
|
|
412
|
+
const lastMatched =
|
|
413
|
+
normalizedPrompt.length > 0 &&
|
|
414
|
+
(lastTurn.includes(normalizedPrompt) ||
|
|
415
|
+
(normalizedPromptPrefix.length > 30 && lastTurn.includes(normalizedPromptPrefix)));
|
|
416
|
+
const baseline = ${baselineLiteral};
|
|
417
|
+
const hasNewTurn = baseline < 0 ? false : normalizedTurns.length > baseline;
|
|
418
|
+
const stopVisible = Boolean(document.querySelector(${stopSelectorLiteral}));
|
|
419
|
+
const assistantVisible = Boolean(
|
|
420
|
+
document.querySelector(${assistantSelectorLiteral}) ||
|
|
421
|
+
document.querySelector('[data-testid*="assistant"]'),
|
|
422
|
+
);
|
|
423
|
+
// Learned: composer clearing + stop button or assistant presence is a reliable fallback signal.
|
|
324
424
|
const editorValue = editor?.innerText ?? '';
|
|
325
425
|
const fallbackValue = fallback?.value ?? '';
|
|
326
|
-
const
|
|
426
|
+
const activeEmpty =
|
|
427
|
+
activeInputs.length === 0 ? null : activeInputs.every((node) => !String(readValue(node)).trim());
|
|
428
|
+
const composerCleared = activeEmpty ?? !(String(editorValue).trim() || String(fallbackValue).trim());
|
|
327
429
|
const href = typeof location === 'object' && location.href ? location.href : '';
|
|
328
430
|
const inConversation = /\\/c\\//.test(href);
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
431
|
+
return {
|
|
432
|
+
baseline,
|
|
433
|
+
userMatched,
|
|
434
|
+
prefixMatched,
|
|
435
|
+
lastMatched,
|
|
436
|
+
hasNewTurn,
|
|
437
|
+
stopVisible,
|
|
335
438
|
assistantVisible,
|
|
336
439
|
composerCleared,
|
|
337
440
|
inConversation,
|
|
@@ -346,12 +449,14 @@ async function verifyPromptCommitted(Runtime, prompt, timeoutMs, logger, baselin
|
|
|
346
449
|
const { result } = await Runtime.evaluate({ expression: script, returnByValue: true });
|
|
347
450
|
const info = result.value;
|
|
348
451
|
const turnsCount = result.value?.turnsCount;
|
|
349
|
-
|
|
452
|
+
const matchesPrompt = Boolean(info?.lastMatched || info?.userMatched || info?.prefixMatched);
|
|
453
|
+
const baselineUnknown = typeof info?.baseline === 'number' ? info.baseline < 0 : baselineLiteral < 0;
|
|
454
|
+
if (matchesPrompt && (baselineUnknown || info?.hasNewTurn)) {
|
|
350
455
|
return typeof turnsCount === 'number' && Number.isFinite(turnsCount) ? turnsCount : null;
|
|
351
456
|
}
|
|
352
457
|
const fallbackCommit = info?.composerCleared &&
|
|
353
|
-
(
|
|
354
|
-
|
|
458
|
+
Boolean(info?.hasNewTurn) &&
|
|
459
|
+
((info?.stopVisible ?? false) || info?.assistantVisible || info?.inConversation);
|
|
355
460
|
if (fallbackCommit) {
|
|
356
461
|
return typeof turnsCount === 'number' && Number.isFinite(turnsCount) ? turnsCount : null;
|
|
357
462
|
}
|
|
@@ -374,3 +479,7 @@ async function verifyPromptCommitted(Runtime, prompt, timeoutMs, logger, baselin
|
|
|
374
479
|
}
|
|
375
480
|
throw new Error('Prompt did not appear in conversation before timeout (send may have failed)');
|
|
376
481
|
}
|
|
482
|
+
// biome-ignore lint/style/useNamingConvention: test-only export used in vitest suite
|
|
483
|
+
export const __test__ = {
|
|
484
|
+
verifyPromptCommitted,
|
|
485
|
+
};
|
|
@@ -7,6 +7,7 @@ import { promisify } from 'node:util';
|
|
|
7
7
|
import CDP from 'chrome-remote-interface';
|
|
8
8
|
import { launch, Launcher } from 'chrome-launcher';
|
|
9
9
|
import { cleanupStaleProfileState } from './profileState.js';
|
|
10
|
+
import { delay } from './utils.js';
|
|
10
11
|
const execFileAsync = promisify(execFile);
|
|
11
12
|
export async function launchChrome(config, userDataDir, logger) {
|
|
12
13
|
const connectHost = resolveRemoteDebugHost();
|
|
@@ -181,17 +182,32 @@ async function connectToNewTarget(host, port, url, logger, messages) {
|
|
|
181
182
|
}
|
|
182
183
|
return null;
|
|
183
184
|
}
|
|
184
|
-
export async function connectWithNewTab(port, logger, initialUrl, host) {
|
|
185
|
+
export async function connectWithNewTab(port, logger, initialUrl, host, options) {
|
|
185
186
|
const effectiveHost = host ?? '127.0.0.1';
|
|
186
187
|
const url = initialUrl ?? 'about:blank';
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
188
|
+
const fallbackToDefault = options?.fallbackToDefault ?? true;
|
|
189
|
+
const retries = Math.max(0, options?.retries ?? 0);
|
|
190
|
+
const retryDelayMs = Math.max(0, options?.retryDelayMs ?? 250);
|
|
191
|
+
const fallbackLabel = fallbackToDefault ? 'falling back to default target.' : 'strict mode: not falling back.';
|
|
192
|
+
let attempt = 0;
|
|
193
|
+
while (attempt <= retries) {
|
|
194
|
+
const targetConnection = await connectToNewTarget(effectiveHost, port, url, logger, {
|
|
195
|
+
opened: (targetId) => `Opened isolated browser tab (target=${targetId})`,
|
|
196
|
+
openFailed: (message) => `Failed to open isolated browser tab (${message}); ${fallbackLabel}`,
|
|
197
|
+
attachFailed: (targetId, message) => `Failed to attach to isolated browser tab ${targetId} (${message}); ${fallbackLabel}`,
|
|
198
|
+
closeFailed: (targetId, message) => `Failed to close unused browser tab ${targetId}: ${message}`,
|
|
199
|
+
});
|
|
200
|
+
if (targetConnection) {
|
|
201
|
+
return targetConnection;
|
|
202
|
+
}
|
|
203
|
+
if (attempt >= retries) {
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
attempt += 1;
|
|
207
|
+
await delay(retryDelayMs * attempt);
|
|
208
|
+
}
|
|
209
|
+
if (!fallbackToDefault) {
|
|
210
|
+
throw new Error('Failed to open isolated browser tab; refusing to attach to default target.');
|
|
195
211
|
}
|
|
196
212
|
const client = await connectToChrome(port, logger, effectiveHost);
|
|
197
213
|
return { client };
|
|
@@ -12,6 +12,13 @@ export const DEFAULT_BROWSER_CONFIG = {
|
|
|
12
12
|
timeoutMs: 1_200_000,
|
|
13
13
|
debugPort: null,
|
|
14
14
|
inputTimeoutMs: 60_000,
|
|
15
|
+
assistantRecheckDelayMs: 0,
|
|
16
|
+
assistantRecheckTimeoutMs: 120_000,
|
|
17
|
+
reuseChromeWaitMs: 10_000,
|
|
18
|
+
profileLockTimeoutMs: 300_000,
|
|
19
|
+
autoReattachDelayMs: 0,
|
|
20
|
+
autoReattachIntervalMs: 0,
|
|
21
|
+
autoReattachTimeoutMs: 120_000,
|
|
15
22
|
cookieSync: true,
|
|
16
23
|
cookieNames: null,
|
|
17
24
|
cookieSyncWaitMs: 0,
|
|
@@ -57,6 +64,13 @@ export function resolveBrowserConfig(config) {
|
|
|
57
64
|
timeoutMs: config?.timeoutMs ?? DEFAULT_BROWSER_CONFIG.timeoutMs,
|
|
58
65
|
debugPort: config?.debugPort ?? debugPortEnv ?? DEFAULT_BROWSER_CONFIG.debugPort,
|
|
59
66
|
inputTimeoutMs: config?.inputTimeoutMs ?? DEFAULT_BROWSER_CONFIG.inputTimeoutMs,
|
|
67
|
+
assistantRecheckDelayMs: config?.assistantRecheckDelayMs ?? DEFAULT_BROWSER_CONFIG.assistantRecheckDelayMs,
|
|
68
|
+
assistantRecheckTimeoutMs: config?.assistantRecheckTimeoutMs ?? DEFAULT_BROWSER_CONFIG.assistantRecheckTimeoutMs,
|
|
69
|
+
reuseChromeWaitMs: config?.reuseChromeWaitMs ?? DEFAULT_BROWSER_CONFIG.reuseChromeWaitMs,
|
|
70
|
+
profileLockTimeoutMs: config?.profileLockTimeoutMs ?? DEFAULT_BROWSER_CONFIG.profileLockTimeoutMs,
|
|
71
|
+
autoReattachDelayMs: config?.autoReattachDelayMs ?? DEFAULT_BROWSER_CONFIG.autoReattachDelayMs,
|
|
72
|
+
autoReattachIntervalMs: config?.autoReattachIntervalMs ?? DEFAULT_BROWSER_CONFIG.autoReattachIntervalMs,
|
|
73
|
+
autoReattachTimeoutMs: config?.autoReattachTimeoutMs ?? DEFAULT_BROWSER_CONFIG.autoReattachTimeoutMs,
|
|
60
74
|
cookieSync: config?.cookieSync ?? cookieSyncDefault,
|
|
61
75
|
cookieNames: config?.cookieNames ?? DEFAULT_BROWSER_CONFIG.cookieNames,
|
|
62
76
|
cookieSyncWaitMs: config?.cookieSyncWaitMs ?? DEFAULT_BROWSER_CONFIG.cookieSyncWaitMs,
|