@steipete/oracle 0.9.0 → 0.11.0
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/LICENSE +1 -1
- package/README.md +107 -49
- package/dist/bin/oracle-cli.js +551 -410
- package/dist/bin/oracle-mcp.js +2 -2
- package/dist/bin/oracle.js +165 -279
- package/dist/scripts/agent-send.js +31 -31
- package/dist/scripts/check.js +6 -6
- package/dist/scripts/debug/extract-chatgpt-response.js +10 -10
- package/dist/scripts/docs-list.js +30 -30
- package/dist/scripts/git-policy.js +25 -23
- package/dist/scripts/run-cli.js +8 -8
- package/dist/scripts/runner.js +203 -195
- package/dist/scripts/test-browser.js +21 -18
- package/dist/scripts/test-remote-chrome.js +20 -20
- package/dist/src/bridge/connection.js +18 -18
- package/dist/src/bridge/userConfigFile.js +7 -7
- package/dist/src/browser/actions/archiveConversation.js +224 -0
- package/dist/src/browser/actions/assistantResponse.js +175 -101
- package/dist/src/browser/actions/attachmentDataTransfer.js +49 -47
- package/dist/src/browser/actions/attachments.js +246 -150
- package/dist/src/browser/actions/deepResearch.js +662 -0
- package/dist/src/browser/actions/domEvents.js +2 -2
- package/dist/src/browser/actions/modelSelection.js +342 -119
- package/dist/src/browser/actions/navigation.js +183 -137
- package/dist/src/browser/actions/projectSources.js +491 -0
- package/dist/src/browser/actions/promptComposer.js +152 -91
- package/dist/src/browser/actions/remoteFileTransfer.js +10 -10
- package/dist/src/browser/actions/thinkingStatus.js +391 -0
- package/dist/src/browser/actions/thinkingTime.js +207 -110
- package/dist/src/browser/artifacts.js +150 -0
- package/dist/src/browser/attachRunning.js +31 -0
- package/dist/src/browser/chatgptImages.js +315 -0
- package/dist/src/browser/chromeLifecycle.js +276 -63
- package/dist/src/browser/config.js +59 -16
- package/dist/src/browser/constants.js +25 -12
- package/dist/src/browser/controlPlan.js +81 -0
- package/dist/src/browser/cookies.js +19 -19
- package/dist/src/browser/detect.js +250 -77
- package/dist/src/browser/domDebug.js +50 -1
- package/dist/src/browser/index.js +1559 -692
- package/dist/src/browser/liveTabs.js +434 -0
- package/dist/src/browser/modelStrategy.js +1 -1
- package/dist/src/browser/pageActions.js +5 -5
- package/dist/src/browser/policies.js +16 -13
- package/dist/src/browser/profileState.js +127 -42
- package/dist/src/browser/projectSourcesRunner.js +366 -0
- package/dist/src/browser/prompt.js +72 -42
- package/dist/src/browser/promptSummary.js +5 -5
- package/dist/src/browser/providerDomFlow.js +1 -1
- package/dist/src/browser/providers/chatgptDomProvider.js +9 -9
- package/dist/src/browser/providers/geminiDeepThinkDomProvider.js +51 -42
- package/dist/src/browser/providers/index.js +2 -2
- package/dist/src/browser/reattach.js +178 -73
- package/dist/src/browser/reattachHelpers.js +32 -27
- package/dist/src/browser/sessionRunner.js +89 -25
- package/dist/src/browser/tabLeaseRegistry.js +182 -0
- package/dist/src/browser/utils.js +9 -9
- package/dist/src/browserMode.js +1 -1
- package/dist/src/cli/bridge/claudeConfig.js +24 -20
- package/dist/src/cli/bridge/client.js +28 -20
- package/dist/src/cli/bridge/codexConfig.js +16 -16
- package/dist/src/cli/bridge/doctor.js +47 -39
- package/dist/src/cli/bridge/host.js +58 -56
- package/dist/src/cli/browserConfig.js +102 -48
- package/dist/src/cli/browserDefaults.js +51 -26
- package/dist/src/cli/browserTabs.js +228 -0
- package/dist/src/cli/bundleWarnings.js +1 -1
- package/dist/src/cli/clipboard.js +11 -2
- package/dist/src/cli/detach.js +2 -2
- package/dist/src/cli/dryRun.js +62 -26
- package/dist/src/cli/duplicatePromptGuard.js +12 -4
- package/dist/src/cli/engine.js +9 -9
- package/dist/src/cli/errorUtils.js +1 -1
- package/dist/src/cli/fileSize.js +3 -3
- package/dist/src/cli/format.js +2 -2
- package/dist/src/cli/help.js +28 -28
- package/dist/src/cli/hiddenAliases.js +3 -3
- package/dist/src/cli/markdownBundle.js +7 -7
- package/dist/src/cli/markdownRenderer.js +15 -15
- package/dist/src/cli/notifier.js +77 -67
- package/dist/src/cli/options.js +131 -106
- package/dist/src/cli/oscUtils.js +1 -1
- package/dist/src/cli/projectSources.js +116 -0
- package/dist/src/cli/promptRequirement.js +2 -2
- package/dist/src/cli/renderOutput.js +1 -1
- package/dist/src/cli/rootAlias.js +1 -1
- package/dist/src/cli/runOptions.js +32 -28
- package/dist/src/cli/sessionCommand.js +82 -21
- package/dist/src/cli/sessionDisplay.js +213 -87
- package/dist/src/cli/sessionLineage.js +6 -2
- package/dist/src/cli/sessionRunner.js +149 -95
- package/dist/src/cli/sessionTable.js +26 -23
- package/dist/src/cli/stdin.js +22 -0
- package/dist/src/cli/tagline.js +121 -124
- package/dist/src/cli/tui/index.js +139 -128
- package/dist/src/cli/writeOutputPath.js +5 -5
- package/dist/src/config.js +7 -7
- package/dist/src/gemini-web/browserSessionManager.js +19 -15
- package/dist/src/gemini-web/client.js +76 -70
- package/dist/src/gemini-web/executionMode.js +6 -8
- package/dist/src/gemini-web/executor.js +98 -93
- package/dist/src/gemini-web/index.js +1 -1
- package/dist/src/mcp/consultPresets.js +19 -0
- package/dist/src/mcp/server.js +18 -12
- package/dist/src/mcp/tools/consult.js +246 -67
- package/dist/src/mcp/tools/projectSources.js +123 -0
- package/dist/src/mcp/tools/sessionResources.js +12 -12
- package/dist/src/mcp/tools/sessions.js +26 -17
- package/dist/src/mcp/types.js +12 -5
- package/dist/src/mcp/utils.js +21 -8
- package/dist/src/oracle/background.js +15 -15
- package/dist/src/oracle/claude.js +53 -25
- package/dist/src/oracle/client.js +50 -41
- package/dist/src/oracle/config.js +96 -66
- package/dist/src/oracle/errors.js +38 -38
- package/dist/src/oracle/files.js +55 -46
- package/dist/src/oracle/finishLine.js +10 -8
- package/dist/src/oracle/format.js +3 -3
- package/dist/src/oracle/gemini.js +37 -33
- package/dist/src/oracle/logging.js +7 -7
- package/dist/src/oracle/markdown.js +28 -28
- package/dist/src/oracle/modelResolver.js +16 -16
- package/dist/src/oracle/multiModelRunner.js +12 -12
- package/dist/src/oracle/oscProgress.js +8 -8
- package/dist/src/oracle/promptAssembly.js +6 -3
- package/dist/src/oracle/request.js +16 -13
- package/dist/src/oracle/run.js +160 -135
- package/dist/src/oracle/runUtils.js +8 -5
- package/dist/src/oracle/tokenEstimate.js +6 -6
- package/dist/src/oracle/tokenStats.js +5 -5
- package/dist/src/oracle/tokenStringifier.js +5 -5
- package/dist/src/oracle.js +12 -12
- package/dist/src/oracleHome.js +3 -3
- package/dist/src/projectSources/plan.js +27 -0
- package/dist/src/projectSources/url.js +23 -0
- package/dist/src/remote/client.js +25 -25
- package/dist/src/remote/health.js +20 -20
- package/dist/src/remote/remoteServiceConfig.js +9 -9
- package/dist/src/remote/server.js +129 -118
- package/dist/src/sessionManager.js +78 -75
- package/dist/src/sessionStore.js +3 -3
- package/dist/src/version.js +10 -10
- package/dist/vendor/oracle-notifier/README.md +2 -0
- package/package.json +67 -62
- package/vendor/oracle-notifier/README.md +2 -0
- package/dist/markdansi/types/index.js +0 -4
- package/dist/oracle/bin/oracle-cli.js +0 -472
- package/dist/oracle/src/browser/actions/assistantResponse.js +0 -471
- package/dist/oracle/src/browser/actions/attachments.js +0 -82
- package/dist/oracle/src/browser/actions/modelSelection.js +0 -190
- package/dist/oracle/src/browser/actions/navigation.js +0 -75
- package/dist/oracle/src/browser/actions/promptComposer.js +0 -167
- package/dist/oracle/src/browser/chromeLifecycle.js +0 -104
- package/dist/oracle/src/browser/config.js +0 -33
- package/dist/oracle/src/browser/constants.js +0 -40
- package/dist/oracle/src/browser/cookies.js +0 -210
- package/dist/oracle/src/browser/domDebug.js +0 -36
- package/dist/oracle/src/browser/index.js +0 -331
- package/dist/oracle/src/browser/pageActions.js +0 -5
- package/dist/oracle/src/browser/prompt.js +0 -88
- package/dist/oracle/src/browser/promptSummary.js +0 -20
- package/dist/oracle/src/browser/sessionRunner.js +0 -80
- package/dist/oracle/src/browser/utils.js +0 -62
- package/dist/oracle/src/browserMode.js +0 -1
- package/dist/oracle/src/cli/browserConfig.js +0 -44
- package/dist/oracle/src/cli/dryRun.js +0 -59
- package/dist/oracle/src/cli/engine.js +0 -17
- package/dist/oracle/src/cli/errorUtils.js +0 -9
- package/dist/oracle/src/cli/help.js +0 -70
- package/dist/oracle/src/cli/markdownRenderer.js +0 -15
- package/dist/oracle/src/cli/options.js +0 -103
- package/dist/oracle/src/cli/promptRequirement.js +0 -14
- package/dist/oracle/src/cli/rootAlias.js +0 -30
- package/dist/oracle/src/cli/sessionCommand.js +0 -77
- package/dist/oracle/src/cli/sessionDisplay.js +0 -270
- package/dist/oracle/src/cli/sessionRunner.js +0 -94
- package/dist/oracle/src/heartbeat.js +0 -43
- package/dist/oracle/src/oracle/client.js +0 -48
- package/dist/oracle/src/oracle/config.js +0 -29
- package/dist/oracle/src/oracle/errors.js +0 -101
- package/dist/oracle/src/oracle/files.js +0 -220
- package/dist/oracle/src/oracle/format.js +0 -33
- package/dist/oracle/src/oracle/fsAdapter.js +0 -7
- package/dist/oracle/src/oracle/oscProgress.js +0 -60
- package/dist/oracle/src/oracle/request.js +0 -48
- package/dist/oracle/src/oracle/run.js +0 -444
- package/dist/oracle/src/oracle/tokenStats.js +0 -39
- package/dist/oracle/src/oracle/types.js +0 -1
- package/dist/oracle/src/oracle.js +0 -9
- package/dist/oracle/src/sessionManager.js +0 -205
- package/dist/oracle/src/version.js +0 -39
- package/dist/scripts/chrome/browser-tools.js +0 -295
- package/dist/src/browser/profileSync.js +0 -141
- /package/dist/{oracle/src/browser → src/projectSources}/types.js +0 -0
|
@@ -1,57 +1,62 @@
|
|
|
1
|
-
import fs from
|
|
2
|
-
import path from
|
|
3
|
-
import { CHATGPT_URL, DEFAULT_MODEL_STRATEGY, DEFAULT_MODEL_TARGET, isTemporaryChatUrl, normalizeChatgptUrl, parseDuration } from
|
|
4
|
-
import { normalizeBrowserModelStrategy } from
|
|
5
|
-
import { getOracleHomeDir } from
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { CHATGPT_URL, DEFAULT_MODEL_STRATEGY, DEFAULT_MODEL_TARGET, isTemporaryChatUrl, normalizeChatgptUrl, parseDuration, } from "../browserMode.js";
|
|
4
|
+
import { normalizeBrowserModelStrategy } from "../browser/modelStrategy.js";
|
|
5
|
+
import { getOracleHomeDir } from "../oracleHome.js";
|
|
6
6
|
const DEFAULT_BROWSER_TIMEOUT_MS = 1_200_000;
|
|
7
7
|
const DEFAULT_BROWSER_INPUT_TIMEOUT_MS = 60_000;
|
|
8
8
|
const DEFAULT_BROWSER_RECHECK_TIMEOUT_MS = 120_000;
|
|
9
9
|
const DEFAULT_BROWSER_AUTO_REATTACH_TIMEOUT_MS = 120_000;
|
|
10
|
-
const DEFAULT_CHROME_PROFILE =
|
|
10
|
+
const DEFAULT_CHROME_PROFILE = "Default";
|
|
11
11
|
// Ordered array: most specific models first to ensure correct selection.
|
|
12
12
|
// The browser label is passed to the model picker which fuzzy-matches against ChatGPT's UI.
|
|
13
13
|
const BROWSER_MODEL_LABELS = [
|
|
14
14
|
// Most specific first (e.g., "gpt-5.2-thinking" before "gpt-5.2")
|
|
15
|
-
[
|
|
16
|
-
[
|
|
17
|
-
[
|
|
18
|
-
[
|
|
19
|
-
[
|
|
20
|
-
[
|
|
15
|
+
["gpt-5.5-pro", "GPT-5.5 Pro"],
|
|
16
|
+
["gpt-5.5", "Thinking 5.5"],
|
|
17
|
+
["gpt-5.4-pro", "GPT-5.4 Pro"],
|
|
18
|
+
["gpt-5.2-thinking", "GPT-5.2 Thinking"],
|
|
19
|
+
["gpt-5.2-instant", "GPT-5.2 Instant"],
|
|
20
|
+
["gpt-5.2-pro", "GPT-5.5 Pro"],
|
|
21
|
+
["gpt-5.1-pro", "GPT-5.5 Pro"],
|
|
22
|
+
["gpt-5-pro", "GPT-5.5 Pro"],
|
|
21
23
|
// Base models last (least specific)
|
|
22
|
-
[
|
|
23
|
-
[
|
|
24
|
-
[
|
|
25
|
-
[
|
|
26
|
-
[
|
|
24
|
+
["gpt-5.4", "Thinking 5.4"],
|
|
25
|
+
["gpt-5.2", "GPT-5.2"], // Selects "Auto" in ChatGPT UI
|
|
26
|
+
["gpt-5.1", "GPT-5.2"], // Legacy alias → Auto
|
|
27
|
+
["gemini-3-pro", "Gemini 3 Pro"],
|
|
28
|
+
["gemini-3-pro-deep-think", "gemini-3-deep-think"],
|
|
27
29
|
];
|
|
28
30
|
export function normalizeChatGptModelForBrowser(model) {
|
|
29
31
|
const normalized = model.toLowerCase();
|
|
30
|
-
if (!normalized.startsWith(
|
|
32
|
+
if (!normalized.startsWith("gpt-") || normalized.includes("codex")) {
|
|
31
33
|
return model;
|
|
32
34
|
}
|
|
33
|
-
if (normalized ===
|
|
35
|
+
if (normalized === "gpt-5.5-pro" ||
|
|
36
|
+
normalized === "gpt-5.5" ||
|
|
37
|
+
normalized === "gpt-5.4-pro" ||
|
|
38
|
+
normalized === "gpt-5.4") {
|
|
34
39
|
return normalized;
|
|
35
40
|
}
|
|
36
41
|
// Pro variants: resolve to the latest Pro model in ChatGPT.
|
|
37
|
-
if (normalized ===
|
|
38
|
-
return
|
|
42
|
+
if (normalized === "gpt-5-pro" || normalized === "gpt-5.1-pro" || normalized === "gpt-5.2-pro") {
|
|
43
|
+
return "gpt-5.5-pro";
|
|
39
44
|
}
|
|
40
45
|
// Explicit model variants: keep as-is (they have their own browser labels)
|
|
41
|
-
if (normalized ===
|
|
46
|
+
if (normalized === "gpt-5.2-thinking" || normalized === "gpt-5.2-instant") {
|
|
42
47
|
return normalized;
|
|
43
48
|
}
|
|
44
49
|
// Legacy aliases: map to base GPT-5.2 (Auto)
|
|
45
|
-
if (normalized ===
|
|
46
|
-
return
|
|
50
|
+
if (normalized === "gpt-5.1") {
|
|
51
|
+
return "gpt-5.2";
|
|
47
52
|
}
|
|
48
53
|
return model;
|
|
49
54
|
}
|
|
50
55
|
export async function buildBrowserConfig(options) {
|
|
51
56
|
const desiredModelOverride = options.browserModelLabel?.trim();
|
|
52
|
-
const normalizedOverride = desiredModelOverride?.toLowerCase() ??
|
|
57
|
+
const normalizedOverride = desiredModelOverride?.toLowerCase() ?? "";
|
|
53
58
|
const baseModel = options.model.toLowerCase();
|
|
54
|
-
const isChatGptModel = baseModel.startsWith(
|
|
59
|
+
const isChatGptModel = baseModel.startsWith("gpt-") && !baseModel.includes("codex");
|
|
55
60
|
const shouldUseOverride = !isChatGptModel && normalizedOverride.length > 0 && normalizedOverride !== baseModel;
|
|
56
61
|
const modelStrategy = normalizeBrowserModelStrategy(options.browserModelStrategy) ?? DEFAULT_MODEL_STRATEGY;
|
|
57
62
|
const cookieNames = parseCookieNames(options.browserCookieNames ?? process.env.ORACLE_BROWSER_COOKIE_NAMES);
|
|
@@ -62,13 +67,18 @@ export async function buildBrowserConfig(options) {
|
|
|
62
67
|
envFile: process.env.ORACLE_BROWSER_COOKIES_FILE,
|
|
63
68
|
cwd: process.cwd(),
|
|
64
69
|
});
|
|
65
|
-
if (inline?.source?.startsWith(
|
|
70
|
+
if (inline?.source?.startsWith("home:") && options.browserNoCookieSync !== true) {
|
|
66
71
|
inline = undefined;
|
|
67
72
|
}
|
|
68
73
|
let remoteChrome;
|
|
69
74
|
if (options.remoteChrome) {
|
|
70
75
|
remoteChrome = parseRemoteChromeTarget(options.remoteChrome);
|
|
71
76
|
}
|
|
77
|
+
const attachRunning = options.browserAttachRunning === true;
|
|
78
|
+
validateAttachRunningOptions(options, {
|
|
79
|
+
attachRunning,
|
|
80
|
+
hasInlineCookies: Boolean(inline?.cookies),
|
|
81
|
+
});
|
|
72
82
|
const rawUrl = options.chatgptUrl ?? options.browserUrl;
|
|
73
83
|
const url = rawUrl ? normalizeChatgptUrl(rawUrl, CHATGPT_URL) : undefined;
|
|
74
84
|
const desiredModel = isChatGptModel
|
|
@@ -76,17 +86,23 @@ export async function buildBrowserConfig(options) {
|
|
|
76
86
|
: shouldUseOverride
|
|
77
87
|
? desiredModelOverride
|
|
78
88
|
: mapModelToBrowserLabel(options.model);
|
|
79
|
-
if (modelStrategy ===
|
|
80
|
-
|
|
89
|
+
if (modelStrategy === "select" &&
|
|
90
|
+
url &&
|
|
91
|
+
isTemporaryChatUrl(url) &&
|
|
92
|
+
/\bpro\b/i.test(desiredModel ?? "")) {
|
|
93
|
+
throw new Error("Temporary Chat mode does not expose Pro models in the ChatGPT model picker. " +
|
|
81
94
|
'Remove "temporary-chat=true" from --chatgpt-url (or omit --chatgpt-url), or use a non-Pro model (e.g. --model gpt-5.2).');
|
|
82
95
|
}
|
|
83
96
|
return {
|
|
84
97
|
chromeProfile: options.browserChromeProfile ?? DEFAULT_CHROME_PROFILE,
|
|
85
98
|
chromePath: options.browserChromePath ?? null,
|
|
86
99
|
chromeCookiePath: options.browserCookiePath ?? null,
|
|
100
|
+
attachRunning,
|
|
87
101
|
url,
|
|
88
102
|
debugPort: selectBrowserPort(options),
|
|
89
|
-
timeoutMs: options.browserTimeout
|
|
103
|
+
timeoutMs: options.browserTimeout
|
|
104
|
+
? parseDuration(options.browserTimeout, DEFAULT_BROWSER_TIMEOUT_MS)
|
|
105
|
+
: undefined,
|
|
90
106
|
inputTimeoutMs: options.browserInputTimeout
|
|
91
107
|
? parseDuration(options.browserInputTimeout, DEFAULT_BROWSER_INPUT_TIMEOUT_MS)
|
|
92
108
|
: undefined,
|
|
@@ -96,10 +112,13 @@ export async function buildBrowserConfig(options) {
|
|
|
96
112
|
assistantRecheckTimeoutMs: options.browserRecheckTimeout
|
|
97
113
|
? parseDuration(options.browserRecheckTimeout, DEFAULT_BROWSER_RECHECK_TIMEOUT_MS)
|
|
98
114
|
: undefined,
|
|
99
|
-
reuseChromeWaitMs: options.browserReuseWait
|
|
115
|
+
reuseChromeWaitMs: options.browserReuseWait
|
|
116
|
+
? parseDuration(options.browserReuseWait, 0)
|
|
117
|
+
: undefined,
|
|
100
118
|
profileLockTimeoutMs: options.browserProfileLockTimeout
|
|
101
119
|
? parseDuration(options.browserProfileLockTimeout, 0)
|
|
102
120
|
: undefined,
|
|
121
|
+
maxConcurrentTabs: parseMaxConcurrentTabs(options.browserMaxConcurrentTabs),
|
|
103
122
|
autoReattachDelayMs: options.browserAutoReattachDelay
|
|
104
123
|
? parseDuration(options.browserAutoReattachDelay, 0)
|
|
105
124
|
: undefined,
|
|
@@ -109,7 +128,9 @@ export async function buildBrowserConfig(options) {
|
|
|
109
128
|
autoReattachTimeoutMs: options.browserAutoReattachTimeout
|
|
110
129
|
? parseDuration(options.browserAutoReattachTimeout, DEFAULT_BROWSER_AUTO_REATTACH_TIMEOUT_MS)
|
|
111
130
|
: undefined,
|
|
112
|
-
cookieSyncWaitMs: options.browserCookieWait
|
|
131
|
+
cookieSyncWaitMs: options.browserCookieWait
|
|
132
|
+
? parseDuration(options.browserCookieWait, 0)
|
|
133
|
+
: undefined,
|
|
113
134
|
cookieSync: options.browserNoCookieSync ? false : undefined,
|
|
114
135
|
cookieNames,
|
|
115
136
|
inlineCookies: inline?.cookies,
|
|
@@ -125,9 +146,33 @@ export async function buildBrowserConfig(options) {
|
|
|
125
146
|
// Allow cookie failures by default so runs can continue without Chrome/Keychain secrets.
|
|
126
147
|
allowCookieErrors: options.browserAllowCookieErrors ?? true,
|
|
127
148
|
remoteChrome,
|
|
149
|
+
browserTabRef: options.browserTab ?? undefined,
|
|
128
150
|
thinkingTime: options.browserThinkingTime,
|
|
151
|
+
researchMode: options.browserResearch === "deep" ? "deep" : "off",
|
|
152
|
+
archiveConversations: options.browserArchive,
|
|
129
153
|
};
|
|
130
154
|
}
|
|
155
|
+
function validateAttachRunningOptions(options, { attachRunning, hasInlineCookies, }) {
|
|
156
|
+
if (!attachRunning) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const conflicts = [
|
|
160
|
+
options.browserChromeProfile ? "--browser-chrome-profile" : null,
|
|
161
|
+
options.browserCookiePath ? "--browser-cookie-path" : null,
|
|
162
|
+
options.browserNoCookieSync ? "--browser-no-cookie-sync" : null,
|
|
163
|
+
options.browserHideWindow ? "--browser-hide-window" : null,
|
|
164
|
+
options.browserKeepBrowser ? "--browser-keep-browser" : null,
|
|
165
|
+
options.browserManualLogin ? "--browser-manual-login" : null,
|
|
166
|
+
options.browserManualLoginProfileDir ? "--browser-manual-login-profile-dir" : null,
|
|
167
|
+
hasInlineCookies ? "--browser-inline-cookies/--browser-inline-cookies-file" : null,
|
|
168
|
+
options.browserPort != null || options.browserDebugPort != null
|
|
169
|
+
? "--browser-port/--browser-debug-port"
|
|
170
|
+
: null,
|
|
171
|
+
].filter((value) => Boolean(value));
|
|
172
|
+
if (conflicts.length > 0) {
|
|
173
|
+
throw new Error(`--browser-attach-running cannot be combined with ${conflicts.join(", ")} because attach mode reuses an already-running browser instead of launching and configuring its own Chrome instance.`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
131
176
|
function selectBrowserPort(options) {
|
|
132
177
|
const candidate = options.browserPort ?? options.browserDebugPort;
|
|
133
178
|
if (candidate === undefined || candidate === null)
|
|
@@ -137,6 +182,15 @@ function selectBrowserPort(options) {
|
|
|
137
182
|
}
|
|
138
183
|
return candidate;
|
|
139
184
|
}
|
|
185
|
+
function parseMaxConcurrentTabs(raw) {
|
|
186
|
+
if (!raw)
|
|
187
|
+
return undefined;
|
|
188
|
+
const value = Number.parseInt(raw, 10);
|
|
189
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
190
|
+
throw new Error(`Invalid browser max concurrent tabs: ${raw}. Expected a positive integer.`);
|
|
191
|
+
}
|
|
192
|
+
return Math.trunc(value);
|
|
193
|
+
}
|
|
140
194
|
export function mapModelToBrowserLabel(model) {
|
|
141
195
|
const normalized = normalizeChatGptModelForBrowser(model);
|
|
142
196
|
// Iterate ordered array to find first match (most specific first)
|
|
@@ -148,7 +202,7 @@ export function mapModelToBrowserLabel(model) {
|
|
|
148
202
|
return DEFAULT_MODEL_TARGET;
|
|
149
203
|
}
|
|
150
204
|
export function resolveBrowserModelLabel(input, model) {
|
|
151
|
-
const trimmed = input?.trim?.() ??
|
|
205
|
+
const trimmed = input?.trim?.() ?? "";
|
|
152
206
|
if (!trimmed) {
|
|
153
207
|
return mapModelToBrowserLabel(model);
|
|
154
208
|
}
|
|
@@ -161,7 +215,7 @@ export function resolveBrowserModelLabel(input, model) {
|
|
|
161
215
|
function parseRemoteChromeTarget(raw) {
|
|
162
216
|
const target = raw.trim();
|
|
163
217
|
if (!target) {
|
|
164
|
-
throw new Error(
|
|
218
|
+
throw new Error("Invalid remote-chrome value: expected host:port but received an empty string.");
|
|
165
219
|
}
|
|
166
220
|
const ipv6Match = target.match(/^\[(.+)]:(\d+)$/);
|
|
167
221
|
let host;
|
|
@@ -171,22 +225,22 @@ function parseRemoteChromeTarget(raw) {
|
|
|
171
225
|
portSegment = ipv6Match[2]?.trim();
|
|
172
226
|
}
|
|
173
227
|
else {
|
|
174
|
-
const lastColon = target.lastIndexOf(
|
|
228
|
+
const lastColon = target.lastIndexOf(":");
|
|
175
229
|
if (lastColon === -1) {
|
|
176
230
|
throw new Error(`Invalid remote-chrome format: ${target}. Expected host:port (IPv6 must use [host]:port notation).`);
|
|
177
231
|
}
|
|
178
232
|
host = target.slice(0, lastColon).trim();
|
|
179
233
|
portSegment = target.slice(lastColon + 1).trim();
|
|
180
|
-
if (host.includes(
|
|
234
|
+
if (host.includes(":")) {
|
|
181
235
|
throw new Error(`Invalid remote-chrome format: ${target}. Wrap IPv6 addresses in brackets, e.g. --remote-chrome "[2001:db8::1]:9222".`);
|
|
182
236
|
}
|
|
183
237
|
}
|
|
184
238
|
if (!host) {
|
|
185
239
|
throw new Error(`Invalid remote-chrome format: ${target}. Host portion is missing; expected host:port.`);
|
|
186
240
|
}
|
|
187
|
-
const port = Number.parseInt(portSegment ??
|
|
241
|
+
const port = Number.parseInt(portSegment ?? "", 10);
|
|
188
242
|
if (!Number.isFinite(port) || port <= 0 || port > 65_535) {
|
|
189
|
-
throw new Error(`Invalid remote-chrome port: "${portSegment ??
|
|
243
|
+
throw new Error(`Invalid remote-chrome port: "${portSegment ?? ""}". Expected a number between 1 and 65535.`);
|
|
190
244
|
}
|
|
191
245
|
return { host, port };
|
|
192
246
|
}
|
|
@@ -194,7 +248,7 @@ function parseCookieNames(raw) {
|
|
|
194
248
|
if (!raw)
|
|
195
249
|
return undefined;
|
|
196
250
|
const names = raw
|
|
197
|
-
.split(
|
|
251
|
+
.split(",")
|
|
198
252
|
.map((entry) => entry.trim())
|
|
199
253
|
.filter(Boolean);
|
|
200
254
|
return names.length ? names : undefined;
|
|
@@ -211,7 +265,7 @@ async function resolveInlineCookies({ inlineArg, inlineFileArg, envPayload, envF
|
|
|
211
265
|
try {
|
|
212
266
|
const stat = await fs.stat(resolved);
|
|
213
267
|
if (stat.isFile()) {
|
|
214
|
-
const fileContent = await fs.readFile(resolved,
|
|
268
|
+
const fileContent = await fs.readFile(resolved, "utf8");
|
|
215
269
|
const parsed = parseInlineCookiesPayload(fileContent);
|
|
216
270
|
if (parsed)
|
|
217
271
|
return parsed;
|
|
@@ -224,10 +278,10 @@ async function resolveInlineCookies({ inlineArg, inlineFileArg, envPayload, envF
|
|
|
224
278
|
return parseInlineCookiesPayload(trimmed);
|
|
225
279
|
};
|
|
226
280
|
const sources = [
|
|
227
|
-
{ value: inlineFileArg, allowPath: true, source:
|
|
228
|
-
{ value: inlineArg, allowPath: true, source:
|
|
229
|
-
{ value: envFile, allowPath: true, source:
|
|
230
|
-
{ value: envPayload, allowPath: false, source:
|
|
281
|
+
{ value: inlineFileArg, allowPath: true, source: "inline-file" },
|
|
282
|
+
{ value: inlineArg, allowPath: true, source: "inline-arg" },
|
|
283
|
+
{ value: envFile, allowPath: true, source: "env-file" },
|
|
284
|
+
{ value: envPayload, allowPath: false, source: "env-payload" },
|
|
231
285
|
];
|
|
232
286
|
for (const { value, allowPath, source } of sources) {
|
|
233
287
|
const parsed = await tryLoad(value, allowPath);
|
|
@@ -236,14 +290,14 @@ async function resolveInlineCookies({ inlineArg, inlineFileArg, envPayload, envF
|
|
|
236
290
|
}
|
|
237
291
|
// fallback: ~/.oracle/cookies.{json,base64}
|
|
238
292
|
const oracleHome = getOracleHomeDir();
|
|
239
|
-
const candidates = [
|
|
293
|
+
const candidates = ["cookies.json", "cookies.base64"];
|
|
240
294
|
for (const file of candidates) {
|
|
241
295
|
const fullPath = path.join(oracleHome, file);
|
|
242
296
|
try {
|
|
243
297
|
const stat = await fs.stat(fullPath);
|
|
244
298
|
if (!stat.isFile())
|
|
245
299
|
continue;
|
|
246
|
-
const content = await fs.readFile(fullPath,
|
|
300
|
+
const content = await fs.readFile(fullPath, "utf8");
|
|
247
301
|
const parsed = parseInlineCookiesPayload(content);
|
|
248
302
|
if (parsed)
|
|
249
303
|
return { cookies: parsed, source: `home:${file}` };
|
|
@@ -263,8 +317,8 @@ function parseInlineCookiesPayload(raw) {
|
|
|
263
317
|
let jsonPayload = text;
|
|
264
318
|
// Attempt base64 decode first; fall back to raw text on failure.
|
|
265
319
|
try {
|
|
266
|
-
const decoded = Buffer.from(text,
|
|
267
|
-
if (decoded.trim().startsWith(
|
|
320
|
+
const decoded = Buffer.from(text, "base64").toString("utf8");
|
|
321
|
+
if (decoded.trim().startsWith("[")) {
|
|
268
322
|
jsonPayload = decoded;
|
|
269
323
|
}
|
|
270
324
|
}
|
|
@@ -1,81 +1,106 @@
|
|
|
1
|
-
import { normalizeChatgptUrl, CHATGPT_URL } from
|
|
1
|
+
import { normalizeChatgptUrl, CHATGPT_URL } from "../browserMode.js";
|
|
2
2
|
export function applyBrowserDefaultsFromConfig(options, config, getSource) {
|
|
3
3
|
const browser = config.browser;
|
|
4
4
|
if (!browser)
|
|
5
5
|
return;
|
|
6
6
|
const isUnset = (key) => {
|
|
7
7
|
const source = getSource(key);
|
|
8
|
-
return source === undefined || source ===
|
|
8
|
+
return source === undefined || source === "default";
|
|
9
9
|
};
|
|
10
|
+
const attachRunningRequested = options.browserAttachRunning === true ||
|
|
11
|
+
(isUnset("browserAttachRunning") && browser.attachRunning === true);
|
|
10
12
|
const configuredChatgptUrl = browser.chatgptUrl ?? browser.url;
|
|
11
13
|
const cliChatgptSet = options.chatgptUrl !== undefined || options.browserUrl !== undefined;
|
|
12
|
-
if (isUnset(
|
|
13
|
-
options.chatgptUrl = normalizeChatgptUrl(configuredChatgptUrl ??
|
|
14
|
+
if (isUnset("chatgptUrl") && !cliChatgptSet && configuredChatgptUrl !== undefined) {
|
|
15
|
+
options.chatgptUrl = normalizeChatgptUrl(configuredChatgptUrl ?? "", CHATGPT_URL);
|
|
14
16
|
}
|
|
15
|
-
if (
|
|
17
|
+
if (!attachRunningRequested &&
|
|
18
|
+
isUnset("browserChromeProfile") &&
|
|
19
|
+
browser.chromeProfile !== undefined) {
|
|
16
20
|
options.browserChromeProfile = browser.chromeProfile ?? undefined;
|
|
17
21
|
}
|
|
18
|
-
if (isUnset(
|
|
22
|
+
if (isUnset("browserChromePath") && browser.chromePath !== undefined) {
|
|
19
23
|
options.browserChromePath = browser.chromePath ?? undefined;
|
|
20
24
|
}
|
|
21
|
-
if (
|
|
25
|
+
if (!attachRunningRequested &&
|
|
26
|
+
isUnset("browserCookiePath") &&
|
|
27
|
+
browser.chromeCookiePath !== undefined) {
|
|
22
28
|
options.browserCookiePath = browser.chromeCookiePath ?? undefined;
|
|
23
29
|
}
|
|
24
|
-
if (isUnset(
|
|
30
|
+
if (isUnset("browserAttachRunning") && browser.attachRunning !== undefined) {
|
|
31
|
+
options.browserAttachRunning = browser.attachRunning;
|
|
32
|
+
}
|
|
33
|
+
if (isUnset("browserUrl") && options.browserUrl === undefined && browser.url !== undefined) {
|
|
25
34
|
options.browserUrl = browser.url;
|
|
26
35
|
}
|
|
27
|
-
if (isUnset(
|
|
36
|
+
if (isUnset("browserTimeout") && typeof browser.timeoutMs === "number") {
|
|
28
37
|
options.browserTimeout = String(browser.timeoutMs);
|
|
29
38
|
}
|
|
30
|
-
if (isUnset(
|
|
39
|
+
if (!attachRunningRequested && isUnset("browserPort") && typeof browser.debugPort === "number") {
|
|
31
40
|
options.browserPort = browser.debugPort;
|
|
32
41
|
}
|
|
33
|
-
if (isUnset(
|
|
42
|
+
if (isUnset("browserInputTimeout") && typeof browser.inputTimeoutMs === "number") {
|
|
34
43
|
options.browserInputTimeout = String(browser.inputTimeoutMs);
|
|
35
44
|
}
|
|
36
|
-
if (isUnset(
|
|
45
|
+
if (isUnset("browserRecheckDelay") && typeof browser.assistantRecheckDelayMs === "number") {
|
|
37
46
|
options.browserRecheckDelay = String(browser.assistantRecheckDelayMs);
|
|
38
47
|
}
|
|
39
|
-
if (isUnset(
|
|
48
|
+
if (isUnset("browserRecheckTimeout") && typeof browser.assistantRecheckTimeoutMs === "number") {
|
|
40
49
|
options.browserRecheckTimeout = String(browser.assistantRecheckTimeoutMs);
|
|
41
50
|
}
|
|
42
|
-
if (isUnset(
|
|
51
|
+
if (isUnset("browserReuseWait") && typeof browser.reuseChromeWaitMs === "number") {
|
|
43
52
|
options.browserReuseWait = String(browser.reuseChromeWaitMs);
|
|
44
53
|
}
|
|
45
|
-
if (isUnset(
|
|
54
|
+
if (isUnset("browserProfileLockTimeout") && typeof browser.profileLockTimeoutMs === "number") {
|
|
46
55
|
options.browserProfileLockTimeout = String(browser.profileLockTimeoutMs);
|
|
47
56
|
}
|
|
48
|
-
if (isUnset(
|
|
57
|
+
if (isUnset("browserMaxConcurrentTabs") && typeof browser.maxConcurrentTabs === "number") {
|
|
58
|
+
options.browserMaxConcurrentTabs = String(browser.maxConcurrentTabs);
|
|
59
|
+
}
|
|
60
|
+
if (isUnset("browserAutoReattachDelay") && typeof browser.autoReattachDelayMs === "number") {
|
|
49
61
|
options.browserAutoReattachDelay = String(browser.autoReattachDelayMs);
|
|
50
62
|
}
|
|
51
|
-
if (isUnset(
|
|
63
|
+
if (isUnset("browserAutoReattachInterval") &&
|
|
64
|
+
typeof browser.autoReattachIntervalMs === "number") {
|
|
52
65
|
options.browserAutoReattachInterval = String(browser.autoReattachIntervalMs);
|
|
53
66
|
}
|
|
54
|
-
if (isUnset(
|
|
67
|
+
if (isUnset("browserAutoReattachTimeout") && typeof browser.autoReattachTimeoutMs === "number") {
|
|
55
68
|
options.browserAutoReattachTimeout = String(browser.autoReattachTimeoutMs);
|
|
56
69
|
}
|
|
57
|
-
if (isUnset(
|
|
70
|
+
if (isUnset("browserCookieWait") && typeof browser.cookieSyncWaitMs === "number") {
|
|
58
71
|
options.browserCookieWait = String(browser.cookieSyncWaitMs);
|
|
59
72
|
}
|
|
60
|
-
if (isUnset(
|
|
73
|
+
if (isUnset("browserHeadless") && browser.headless !== undefined) {
|
|
61
74
|
options.browserHeadless = browser.headless;
|
|
62
75
|
}
|
|
63
|
-
if (isUnset(
|
|
76
|
+
if (!attachRunningRequested && isUnset("browserHideWindow") && browser.hideWindow !== undefined) {
|
|
64
77
|
options.browserHideWindow = browser.hideWindow;
|
|
65
78
|
}
|
|
66
|
-
if (
|
|
79
|
+
if (!attachRunningRequested &&
|
|
80
|
+
isUnset("browserKeepBrowser") &&
|
|
81
|
+
browser.keepBrowser !== undefined) {
|
|
67
82
|
options.browserKeepBrowser = browser.keepBrowser;
|
|
68
83
|
}
|
|
69
|
-
if (isUnset(
|
|
84
|
+
if (isUnset("browserModelStrategy") && browser.modelStrategy !== undefined) {
|
|
70
85
|
options.browserModelStrategy = browser.modelStrategy;
|
|
71
86
|
}
|
|
72
|
-
if (isUnset(
|
|
87
|
+
if (isUnset("browserThinkingTime") && browser.thinkingTime !== undefined) {
|
|
73
88
|
options.browserThinkingTime = browser.thinkingTime;
|
|
74
89
|
}
|
|
75
|
-
if (isUnset(
|
|
90
|
+
if (isUnset("browserResearch") && browser.researchMode !== undefined) {
|
|
91
|
+
options.browserResearch = browser.researchMode;
|
|
92
|
+
}
|
|
93
|
+
if (isUnset("browserArchive") && browser.archiveConversations !== undefined) {
|
|
94
|
+
options.browserArchive = browser.archiveConversations;
|
|
95
|
+
}
|
|
96
|
+
if (!attachRunningRequested &&
|
|
97
|
+
isUnset("browserManualLogin") &&
|
|
98
|
+
browser.manualLogin !== undefined) {
|
|
76
99
|
options.browserManualLogin = browser.manualLogin;
|
|
77
100
|
}
|
|
78
|
-
if (
|
|
101
|
+
if (!attachRunningRequested &&
|
|
102
|
+
isUnset("browserManualLoginProfileDir") &&
|
|
103
|
+
browser.manualLoginProfileDir !== undefined) {
|
|
79
104
|
options.browserManualLoginProfileDir = browser.manualLoginProfileDir;
|
|
80
105
|
}
|
|
81
106
|
}
|