@steipete/oracle 0.16.0 → 0.17.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/README.md +72 -337
- package/dist/bin/oracle-cli.js +184 -55
- package/dist/bin/oracle-mcp.js +0 -0
- package/dist/docs-site/.nojekyll +0 -0
- package/dist/docs-site/CNAME +1 -0
- package/dist/docs-site/RELEASING.html +410 -0
- package/dist/docs-site/agents.html +374 -0
- package/dist/docs-site/anthropic.html +368 -0
- package/dist/docs-site/bridge.html +416 -0
- package/dist/docs-site/browser-mode.html +594 -0
- package/dist/docs-site/chromium-forks.html +347 -0
- package/dist/docs-site/cli-reference.html +346 -0
- package/dist/docs-site/configuration.html +462 -0
- package/dist/docs-site/favicon.svg +14 -0
- package/dist/docs-site/followup.html +375 -0
- package/dist/docs-site/gemini.html +383 -0
- package/dist/docs-site/grok.html +325 -0
- package/dist/docs-site/index.html +360 -0
- package/dist/docs-site/install.html +335 -0
- package/dist/docs-site/linux.html +321 -0
- package/dist/docs-site/llms.txt +43 -0
- package/dist/docs-site/manual-tests.html +596 -0
- package/dist/docs-site/mcp.html +391 -0
- package/dist/docs-site/multimodel.html +364 -0
- package/dist/docs-site/mythical-pro-agents.html +360 -0
- package/dist/docs-site/notifier.html +338 -0
- package/dist/docs-site/openai-endpoints.html +410 -0
- package/dist/docs-site/openrouter.html +344 -0
- package/dist/docs-site/quickstart.html +369 -0
- package/dist/docs-site/refactor/ux.html +532 -0
- package/dist/docs-site/sessions.html +389 -0
- package/dist/docs-site/social-card.png +0 -0
- package/dist/docs-site/social-card.svg +79 -0
- package/dist/docs-site/spec.html +363 -0
- package/dist/docs-site/testing.html +320 -0
- package/dist/docs-site/tui-debug.html +326 -0
- package/dist/docs-site/windows-work.html +324 -0
- package/dist/docs-site/windows.html +320 -0
- package/dist/scripts/test-browser.js +1 -25
- package/dist/src/browser/actions/modelSelection.js +36 -34
- package/dist/src/browser/actions/navigation.js +8 -3
- package/dist/src/browser/actions/thinkingTime.js +39 -3
- package/dist/src/browser/cdpLiveness.js +78 -0
- package/dist/src/browser/chromeLifecycle.js +85 -39
- package/dist/src/browser/conversationUrl.js +16 -0
- package/dist/src/browser/conversationUrlMonitor.js +2 -4
- package/dist/src/browser/cookies.js +6 -4
- package/dist/src/browser/index.js +181 -50
- package/dist/src/browser/liveTabs.js +2 -2
- package/dist/src/browser/modelDisplay.js +67 -0
- package/dist/src/browser/reattach.js +14 -1
- package/dist/src/browser/reattachHelpers.js +3 -5
- package/dist/src/browser/reattachability.js +2 -1
- package/dist/src/browser/recoverConversation.js +2 -1
- package/dist/src/browser/sessionRunner.js +9 -10
- package/dist/src/browser/tabLeaseRegistry.js +9 -3
- package/dist/src/browser/wslHost.js +50 -0
- package/dist/src/cli/browserConfig.js +31 -11
- package/dist/src/cli/browserDefaults.js +4 -1
- package/dist/src/cli/detach.js +21 -4
- package/dist/src/cli/dryRun.js +13 -2
- package/dist/src/cli/engine.js +2 -2
- package/dist/src/cli/options.js +4 -0
- package/dist/src/cli/sessionDisplay.js +60 -8
- package/dist/src/cli/sessionLifecycle.js +2 -1
- package/dist/src/cli/sessionRunner.js +159 -62
- package/dist/src/cli/sessionTable.js +5 -1
- package/dist/src/cli/tui/index.js +12 -4
- package/dist/src/duration.js +3 -0
- package/dist/src/gemini-web/client.js +19 -1
- package/dist/src/oracle/modelResolver.js +8 -1
- package/dist/src/oracle/request.js +9 -2
- package/dist/src/oracle/run.js +43 -3
- package/dist/src/remote/server.js +8 -0
- package/dist/src/sessionManager.js +41 -12
- 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 +16 -16
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/CodeResources +0 -0
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/MacOS/OracleNotifier +0 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
export function isWsl() {
|
|
4
|
+
if (process.platform !== "linux")
|
|
5
|
+
return false;
|
|
6
|
+
if (process.env.WSL_DISTRO_NAME)
|
|
7
|
+
return true;
|
|
8
|
+
return os.release().toLowerCase().includes("microsoft");
|
|
9
|
+
}
|
|
10
|
+
export function parseWslResolverHost(resolvConf) {
|
|
11
|
+
for (const line of resolvConf.split("\n")) {
|
|
12
|
+
const match = line.match(/^nameserver\s+([0-9.]+)/);
|
|
13
|
+
if (match?.[1]) {
|
|
14
|
+
return match[1].startsWith("127.") ? "127.0.0.1" : match[1];
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
export function resolveWslHost() {
|
|
20
|
+
if (!isWsl())
|
|
21
|
+
return null;
|
|
22
|
+
try {
|
|
23
|
+
return parseWslResolverHost(readFileSync("/etc/resolv.conf", "utf8"));
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export function resolveWslChromeHost(options = {}) {
|
|
30
|
+
const remoteDebugHost = options.remoteDebugHost === undefined
|
|
31
|
+
? process.env.ORACLE_BROWSER_REMOTE_DEBUG_HOST
|
|
32
|
+
: options.remoteDebugHost;
|
|
33
|
+
const wslHostIp = options.wslHostIp === undefined ? process.env.WSL_HOST_IP : options.wslHostIp;
|
|
34
|
+
const override = remoteDebugHost?.trim() || wslHostIp?.trim();
|
|
35
|
+
if (override)
|
|
36
|
+
return override;
|
|
37
|
+
if (options.resolvConf !== undefined) {
|
|
38
|
+
return options.resolvConf === null ? null : parseWslResolverHost(options.resolvConf);
|
|
39
|
+
}
|
|
40
|
+
return resolveWslHost();
|
|
41
|
+
}
|
|
42
|
+
export function resolveWslChromeLaunchRoute(options = {}) {
|
|
43
|
+
const connectHost = resolveWslChromeHost(options);
|
|
44
|
+
const usePatchedLauncher = Boolean(connectHost && connectHost !== "127.0.0.1");
|
|
45
|
+
return {
|
|
46
|
+
connectHost,
|
|
47
|
+
debugBindAddress: usePatchedLauncher ? "0.0.0.0" : connectHost,
|
|
48
|
+
usePatchedLauncher,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import chalk from "chalk";
|
|
3
4
|
import { normalizeThinkingTimeLevel } from "../oracle/thinkingTime.js";
|
|
4
5
|
import { CHATGPT_URL, DEFAULT_MODEL_STRATEGY, DEFAULT_MODEL_TARGET } from "../browser/constants.js";
|
|
5
6
|
import { normalizeChatgptUrl } from "../browser/utils.js";
|
|
@@ -86,6 +87,7 @@ export async function buildBrowserConfig(options) {
|
|
|
86
87
|
const isChatGptModel = baseModel.startsWith("gpt-") && !baseModel.includes("codex");
|
|
87
88
|
const shouldUseOverride = !isChatGptModel && normalizedOverride.length > 0 && normalizedOverride !== baseModel;
|
|
88
89
|
const modelStrategy = normalizeBrowserModelStrategy(options.browserModelStrategy) ?? DEFAULT_MODEL_STRATEGY;
|
|
90
|
+
assertBrowserModelAvailable(options.model, modelStrategy);
|
|
89
91
|
const cookieNames = parseCookieNames(options.browserCookieNames ?? process.env.ORACLE_BROWSER_COOKIE_NAMES);
|
|
90
92
|
let inline = await resolveInlineCookies({
|
|
91
93
|
inlineArg: options.browserInlineCookies,
|
|
@@ -123,38 +125,38 @@ export async function buildBrowserConfig(options) {
|
|
|
123
125
|
url,
|
|
124
126
|
debugPort: selectBrowserPort(options),
|
|
125
127
|
timeoutMs: options.browserTimeout
|
|
126
|
-
?
|
|
128
|
+
? parseBrowserDuration(options.browserTimeout, "--browser-timeout", DEFAULT_BROWSER_TIMEOUT_MS)
|
|
127
129
|
: undefined,
|
|
128
130
|
inputTimeoutMs: options.browserInputTimeout
|
|
129
|
-
?
|
|
131
|
+
? parseBrowserDuration(options.browserInputTimeout, "--browser-input-timeout", DEFAULT_BROWSER_INPUT_TIMEOUT_MS)
|
|
130
132
|
: undefined,
|
|
131
133
|
attachmentTimeoutMs: options.browserAttachmentTimeout
|
|
132
|
-
?
|
|
134
|
+
? parseBrowserDuration(options.browserAttachmentTimeout, "--browser-attachment-timeout", DEFAULT_BROWSER_ATTACHMENT_TIMEOUT_MS)
|
|
133
135
|
: undefined,
|
|
134
136
|
assistantRecheckDelayMs: options.browserRecheckDelay
|
|
135
|
-
?
|
|
137
|
+
? parseBrowserDuration(options.browserRecheckDelay, "--browser-recheck-delay", 0)
|
|
136
138
|
: undefined,
|
|
137
139
|
assistantRecheckTimeoutMs: options.browserRecheckTimeout
|
|
138
|
-
?
|
|
140
|
+
? parseBrowserDuration(options.browserRecheckTimeout, "--browser-recheck-timeout", DEFAULT_BROWSER_RECHECK_TIMEOUT_MS)
|
|
139
141
|
: undefined,
|
|
140
142
|
reuseChromeWaitMs: options.browserReuseWait
|
|
141
|
-
?
|
|
143
|
+
? parseBrowserDuration(options.browserReuseWait, "--browser-reuse-wait", 0)
|
|
142
144
|
: undefined,
|
|
143
145
|
profileLockTimeoutMs: options.browserProfileLockTimeout
|
|
144
|
-
?
|
|
146
|
+
? parseBrowserDuration(options.browserProfileLockTimeout, "--browser-profile-lock-timeout", 0)
|
|
145
147
|
: undefined,
|
|
146
148
|
maxConcurrentTabs: parseMaxConcurrentTabs(options.browserMaxConcurrentTabs),
|
|
147
149
|
autoReattachDelayMs: options.browserAutoReattachDelay
|
|
148
|
-
?
|
|
150
|
+
? parseBrowserDuration(options.browserAutoReattachDelay, "--browser-auto-reattach-delay", 0)
|
|
149
151
|
: undefined,
|
|
150
152
|
autoReattachIntervalMs: options.browserAutoReattachInterval
|
|
151
|
-
?
|
|
153
|
+
? parseBrowserDuration(options.browserAutoReattachInterval, "--browser-auto-reattach-interval", 0)
|
|
152
154
|
: undefined,
|
|
153
155
|
autoReattachTimeoutMs: options.browserAutoReattachTimeout
|
|
154
|
-
?
|
|
156
|
+
? parseBrowserDuration(options.browserAutoReattachTimeout, "--browser-auto-reattach-timeout", DEFAULT_BROWSER_AUTO_REATTACH_TIMEOUT_MS)
|
|
155
157
|
: undefined,
|
|
156
158
|
cookieSyncWaitMs: options.browserCookieWait
|
|
157
|
-
?
|
|
159
|
+
? parseBrowserDuration(options.browserCookieWait, "--browser-cookie-wait", 0)
|
|
158
160
|
: undefined,
|
|
159
161
|
cookieSync: options.browserNoCookieSync ? false : undefined,
|
|
160
162
|
cookieNames,
|
|
@@ -178,6 +180,17 @@ export async function buildBrowserConfig(options) {
|
|
|
178
180
|
archiveConversations: options.browserArchive,
|
|
179
181
|
};
|
|
180
182
|
}
|
|
183
|
+
function assertBrowserModelAvailable(model, modelStrategy) {
|
|
184
|
+
if (modelStrategy !== "select")
|
|
185
|
+
return;
|
|
186
|
+
const normalized = normalizeChatGptModelForBrowser(model);
|
|
187
|
+
if (normalized !== "gpt-5.2" &&
|
|
188
|
+
normalized !== "gpt-5.2-instant" &&
|
|
189
|
+
normalized !== "gpt-5.2-thinking") {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
throw new Error(`Browser model "${model}" is retired because ChatGPT no longer offers GPT-5.2 base, Instant, or Thinking. Choose a current GPT-5.5/GPT-5.6 browser model, use --browser-model-strategy current to keep ChatGPT's active model, or use --engine api to retain the GPT-5.2 API alias.`);
|
|
193
|
+
}
|
|
181
194
|
function validateAttachRunningOptions(options, { attachRunning, hasInlineCookies, }) {
|
|
182
195
|
if (!attachRunning) {
|
|
183
196
|
return;
|
|
@@ -218,6 +231,13 @@ function parseMaxConcurrentTabs(raw) {
|
|
|
218
231
|
}
|
|
219
232
|
return Math.trunc(value);
|
|
220
233
|
}
|
|
234
|
+
function parseBrowserDuration(raw, optionName, fallbackMs) {
|
|
235
|
+
const parsed = parseDuration(raw, Number.NaN);
|
|
236
|
+
if (Number.isFinite(parsed))
|
|
237
|
+
return parsed;
|
|
238
|
+
console.log(chalk.yellow(`Warning: invalid ${optionName} duration "${raw}"; using fallback ${fallbackMs}ms.`));
|
|
239
|
+
return fallbackMs;
|
|
240
|
+
}
|
|
221
241
|
export function mapModelToBrowserLabel(model) {
|
|
222
242
|
const normalized = normalizeChatGptModelForBrowser(model);
|
|
223
243
|
// Iterate ordered array to find first match (most specific first)
|
|
@@ -11,6 +11,7 @@ export function applyBrowserDefaultsFromConfig(options, config, getSource) {
|
|
|
11
11
|
};
|
|
12
12
|
const attachRunningRequested = options.browserAttachRunning === true ||
|
|
13
13
|
(isUnset("browserAttachRunning") && browser.attachRunning === true);
|
|
14
|
+
const currentModelRequestedByCli = options.browserModelStrategy === "current" && getSource("browserModelStrategy") === "cli";
|
|
14
15
|
const configuredChatgptUrl = browser.chatgptUrl ?? browser.url;
|
|
15
16
|
const cliChatgptSet = options.chatgptUrl !== undefined || options.browserUrl !== undefined;
|
|
16
17
|
if (isUnset("chatgptUrl") && !cliChatgptSet && configuredChatgptUrl !== undefined) {
|
|
@@ -89,7 +90,9 @@ export function applyBrowserDefaultsFromConfig(options, config, getSource) {
|
|
|
89
90
|
if (isUnset("browserModelStrategy") && browser.modelStrategy !== undefined) {
|
|
90
91
|
options.browserModelStrategy = browser.modelStrategy;
|
|
91
92
|
}
|
|
92
|
-
if (
|
|
93
|
+
if (!currentModelRequestedByCli &&
|
|
94
|
+
isUnset("browserThinkingTime") &&
|
|
95
|
+
browser.thinkingTime !== undefined) {
|
|
93
96
|
options.browserThinkingTime = normalizeThinkingTimeLevel(browser.thinkingTime) ?? undefined;
|
|
94
97
|
}
|
|
95
98
|
if (isUnset("browserResearch") && browser.researchMode !== undefined) {
|
package/dist/src/cli/detach.js
CHANGED
|
@@ -1,14 +1,31 @@
|
|
|
1
1
|
import { isProModel } from "../oracle/modelResolver.js";
|
|
2
2
|
export function shouldDetachSession({
|
|
3
3
|
// Params kept for policy tweaks.
|
|
4
|
-
engine, model, waitPreference, disableDetachEnv, }) {
|
|
4
|
+
engine, model, reasoningMode, waitPreference, disableDetachEnv, }) {
|
|
5
5
|
if (disableDetachEnv)
|
|
6
6
|
return false;
|
|
7
|
-
//
|
|
7
|
+
// Keep long local browser Pro work in a separate process even while the CLI
|
|
8
|
+
// stays attached to its session log. If the foreground stream is interrupted,
|
|
9
|
+
// the worker can still finish the browser run and persist the answer.
|
|
10
|
+
if (engine === "browser" && isProModel(model))
|
|
11
|
+
return true;
|
|
12
|
+
// For API runs, explicit --wait keeps execution in the foreground.
|
|
8
13
|
if (waitPreference)
|
|
9
14
|
return false;
|
|
10
|
-
//
|
|
11
|
-
if (isProModel(model) && engine === "api")
|
|
15
|
+
// Pro-tier API runs start detached by default.
|
|
16
|
+
if ((isProModel(model) || reasoningMode === "pro") && engine === "api")
|
|
12
17
|
return true;
|
|
13
18
|
return false;
|
|
14
19
|
}
|
|
20
|
+
export function stopDetachedWorker(workerPid, kill = process.kill) {
|
|
21
|
+
try {
|
|
22
|
+
kill(workerPid, "SIGTERM");
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ESRCH") {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
}
|
package/dist/src/cli/dryRun.js
CHANGED
|
@@ -5,6 +5,7 @@ import { assembleBrowserPrompt } from "../browser/prompt.js";
|
|
|
5
5
|
import { buildTokenEstimateSuffix, formatAttachmentLabel } from "../browser/promptSummary.js";
|
|
6
6
|
import { buildCookiePlan } from "../browser/policies.js";
|
|
7
7
|
import { describeBrowserControlPlan, formatBrowserControlPlan } from "../browser/controlPlan.js";
|
|
8
|
+
import { formatBrowserModelTarget } from "../browser/modelDisplay.js";
|
|
8
9
|
export async function runDryRunSummary({ engine, runOptions, cwd, version, log, browserConfig, }, deps = {}) {
|
|
9
10
|
if (engine === "browser") {
|
|
10
11
|
await runBrowserDryRun({ runOptions, cwd, version, log, browserConfig }, deps);
|
|
@@ -45,7 +46,12 @@ async function runBrowserDryRun({ runOptions, cwd, version, log, browserConfig,
|
|
|
45
46
|
const assemblePromptImpl = deps.assembleBrowserPromptImpl ?? assembleBrowserPrompt;
|
|
46
47
|
const artifacts = await assemblePromptImpl(runOptions, { cwd });
|
|
47
48
|
const suffix = buildTokenEstimateSuffix(artifacts);
|
|
48
|
-
const
|
|
49
|
+
const displayModel = formatBrowserModelTarget({
|
|
50
|
+
model: runOptions.model,
|
|
51
|
+
desiredModel: browserConfig?.desiredModel,
|
|
52
|
+
modelStrategy: browserConfig?.modelStrategy,
|
|
53
|
+
});
|
|
54
|
+
const headerLine = `[dry-run] Oracle (${version}) would launch browser mode (${displayModel}) with ~${artifacts.estimatedInputTokens.toLocaleString()} tokens${suffix}.`;
|
|
49
55
|
log(chalk.cyan(headerLine));
|
|
50
56
|
logBrowserControlPlan(browserConfig, log, "dry-run");
|
|
51
57
|
logBrowserFollowUpSummary(runOptions.browserFollowUps, log, "dry-run");
|
|
@@ -95,7 +101,12 @@ export async function runBrowserPreview({ runOptions, cwd, version, previewMode,
|
|
|
95
101
|
const assemblePromptImpl = deps.assembleBrowserPromptImpl ?? assembleBrowserPrompt;
|
|
96
102
|
const artifacts = await assemblePromptImpl(runOptions, { cwd });
|
|
97
103
|
const suffix = buildTokenEstimateSuffix(artifacts);
|
|
98
|
-
const
|
|
104
|
+
const displayModel = formatBrowserModelTarget({
|
|
105
|
+
model: runOptions.model,
|
|
106
|
+
desiredModel: browserConfig?.desiredModel,
|
|
107
|
+
modelStrategy: browserConfig?.modelStrategy,
|
|
108
|
+
});
|
|
109
|
+
const headerLine = `[preview] Oracle (${version}) browser mode (${displayModel}) with ~${artifacts.estimatedInputTokens.toLocaleString()} tokens${suffix}.`;
|
|
99
110
|
log(chalk.cyan(headerLine));
|
|
100
111
|
logBrowserControlPlan(browserConfig, log, "preview");
|
|
101
112
|
logBrowserFollowUpSummary(runOptions.browserFollowUps, log, "preview");
|
package/dist/src/cli/engine.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isProModel } from "../oracle/modelResolver.js";
|
|
2
|
-
export function defaultWaitPreference(model, engine) {
|
|
2
|
+
export function defaultWaitPreference(model, engine, reasoningMode) {
|
|
3
3
|
// Pro-class API runs can take a long time; prefer non-blocking unless explicitly overridden.
|
|
4
|
-
if (engine === "api" && isProModel(model)) {
|
|
4
|
+
if (engine === "api" && (isProModel(model) || reasoningMode === "pro")) {
|
|
5
5
|
return false;
|
|
6
6
|
}
|
|
7
7
|
return true; // browser or non-pro models are fast enough to block by default
|
package/dist/src/cli/options.js
CHANGED
|
@@ -187,6 +187,10 @@ export function resolveApiModel(modelValue) {
|
|
|
187
187
|
if (normalized.includes("/")) {
|
|
188
188
|
return normalized;
|
|
189
189
|
}
|
|
190
|
+
const gpt56Label = parseBrowserGpt56Label(normalized);
|
|
191
|
+
if (gpt56Label?.variant.split(" ").includes("pro")) {
|
|
192
|
+
throw new InvalidArgumentError("GPT-5.6 Pro is an API reasoning mode, not a model slug. Use --model gpt-5.6-sol --reasoning-mode pro.");
|
|
193
|
+
}
|
|
190
194
|
if (normalized.includes("grok")) {
|
|
191
195
|
return "grok-4.1";
|
|
192
196
|
}
|
|
@@ -12,6 +12,7 @@ import { estimateTokenCount } from "../browser/utils.js";
|
|
|
12
12
|
import { formatSessionTableHeader, formatSessionTableRow, resolveSessionCost, } from "./sessionTable.js";
|
|
13
13
|
import { abbreviateResponseId, buildResponseOwnerIndex, resolveSessionLineage, } from "./sessionLineage.js";
|
|
14
14
|
import { formatSessionExecutionLabel } from "./sessionLifecycle.js";
|
|
15
|
+
import { formatBrowserModelSelectionEvidence, formatSessionBrowserModelWithRequestedKey, resolveSessionBrowserModelDisplayName, } from "../browser/modelDisplay.js";
|
|
15
16
|
const isTty = () => Boolean(process.stdout.isTTY);
|
|
16
17
|
const dim = (text) => (isTty() ? kleur.dim(text) : text);
|
|
17
18
|
export const MAX_RENDER_BYTES = 200_000;
|
|
@@ -185,6 +186,7 @@ export async function attachSession(sessionId, options) {
|
|
|
185
186
|
const isVerbose = Boolean(process.env.ORACLE_VERBOSE_RENDER);
|
|
186
187
|
const runtime = metadata.browser?.runtime;
|
|
187
188
|
const controllerAlive = isProcessAlive(runtime?.controllerPid);
|
|
189
|
+
const workerAlive = isProcessAlive(metadata.lifecycle?.workerPid);
|
|
188
190
|
const hasChromeDisconnect = metadata.response?.incompleteReason === "chrome-disconnected";
|
|
189
191
|
const hasIncompleteCapture = metadata.response?.incompleteReason === "incomplete-capture";
|
|
190
192
|
const statusAllowsReattach = metadata.status === "running" ||
|
|
@@ -204,6 +206,7 @@ export async function attachSession(sessionId, options) {
|
|
|
204
206
|
const canReattach = (statusAllowsReattach || completedDeepResearchPlaceholder) &&
|
|
205
207
|
metadata.mode === "browser" &&
|
|
206
208
|
hasFallbackSessionInfo &&
|
|
209
|
+
!workerAlive &&
|
|
207
210
|
(hasRecoverableConversation ||
|
|
208
211
|
runtime?.promptSubmitted ||
|
|
209
212
|
hasLiveChromeFallback ||
|
|
@@ -311,11 +314,17 @@ export async function attachSession(sessionId, options) {
|
|
|
311
314
|
const usage = run.usage
|
|
312
315
|
? ` tok=${formatTokenCount(run.usage.outputTokens ?? 0)}/${formatTokenCount(run.usage.totalTokens ?? 0)}`
|
|
313
316
|
: "";
|
|
314
|
-
|
|
317
|
+
const modelLabel = (metadata.mode ?? metadata.options?.mode) === "browser"
|
|
318
|
+
? formatSessionBrowserModelWithRequestedKey(metadata, run.model)
|
|
319
|
+
: run.model;
|
|
320
|
+
console.log(`- ${chalk.cyan(modelLabel)} — ${run.status}${usage}`);
|
|
315
321
|
}
|
|
316
322
|
}
|
|
317
323
|
else if (metadata.model) {
|
|
318
|
-
|
|
324
|
+
const modelLabel = (metadata.mode ?? metadata.options?.mode) === "browser"
|
|
325
|
+
? formatSessionBrowserModelWithRequestedKey(metadata)
|
|
326
|
+
: metadata.model;
|
|
327
|
+
console.log(`Model: ${modelLabel}`);
|
|
319
328
|
}
|
|
320
329
|
const browserEvidence = formatBrowserEvidence(metadata);
|
|
321
330
|
if (browserEvidence) {
|
|
@@ -391,6 +400,9 @@ export async function attachSession(sessionId, options) {
|
|
|
391
400
|
if (summary) {
|
|
392
401
|
console.log(`\n${chalk.green.bold(summary)}`);
|
|
393
402
|
}
|
|
403
|
+
if (options?.propagateFailure && metadata.status === "error") {
|
|
404
|
+
process.exitCode = 1;
|
|
405
|
+
}
|
|
394
406
|
return;
|
|
395
407
|
}
|
|
396
408
|
if (wantsRender) {
|
|
@@ -493,6 +505,48 @@ export async function attachSession(sessionId, options) {
|
|
|
493
505
|
}
|
|
494
506
|
}
|
|
495
507
|
}
|
|
508
|
+
if (options?.propagateFailure && latest.status === "error") {
|
|
509
|
+
process.exitCode = 1;
|
|
510
|
+
}
|
|
511
|
+
break;
|
|
512
|
+
}
|
|
513
|
+
const controllerPid = latest.lifecycle?.workerPid ?? latest.browser?.runtime?.controllerPid;
|
|
514
|
+
if (latest.lifecycle?.detached && controllerPid && !isProcessAlive(controllerPid)) {
|
|
515
|
+
const settled = await sessionStore.readSession(sessionId);
|
|
516
|
+
if (!settled) {
|
|
517
|
+
break;
|
|
518
|
+
}
|
|
519
|
+
if (settled.status === "completed" || settled.status === "partial") {
|
|
520
|
+
continue;
|
|
521
|
+
}
|
|
522
|
+
await printNew();
|
|
523
|
+
flushRemainder();
|
|
524
|
+
const message = settled.status === "error"
|
|
525
|
+
? (settled.errorMessage ?? "Detached worker failed.")
|
|
526
|
+
: "Detached worker exited before the session reached a terminal state.";
|
|
527
|
+
const failure = {
|
|
528
|
+
category: "internal",
|
|
529
|
+
message,
|
|
530
|
+
};
|
|
531
|
+
if (settled.model) {
|
|
532
|
+
await sessionStore.updateModelRun(settled.id, settled.model, {
|
|
533
|
+
status: "error",
|
|
534
|
+
completedAt: new Date().toISOString(),
|
|
535
|
+
response: { status: "incomplete", incompleteReason: "incomplete-capture" },
|
|
536
|
+
error: failure,
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
await sessionStore.updateSession(settled.id, {
|
|
540
|
+
status: "error",
|
|
541
|
+
completedAt: new Date().toISOString(),
|
|
542
|
+
errorMessage: message,
|
|
543
|
+
response: { status: "incomplete", incompleteReason: "incomplete-capture" },
|
|
544
|
+
error: failure,
|
|
545
|
+
});
|
|
546
|
+
console.log(chalk.yellow(`${message} Reattach via: ${settled.lifecycle?.reattachCommand}`));
|
|
547
|
+
if (options?.propagateFailure) {
|
|
548
|
+
process.exitCode = 1;
|
|
549
|
+
}
|
|
496
550
|
break;
|
|
497
551
|
}
|
|
498
552
|
await wait(1000);
|
|
@@ -555,11 +609,7 @@ export function formatBrowserEvidence(metadata) {
|
|
|
555
609
|
const lines = [];
|
|
556
610
|
const evidence = browser.modelSelection;
|
|
557
611
|
if (evidence) {
|
|
558
|
-
|
|
559
|
-
const resolved = evidence.resolvedLabel ?? "(unavailable)";
|
|
560
|
-
const strategy = evidence.strategy ?? "(default)";
|
|
561
|
-
const verified = evidence.verified ? "yes" : "no";
|
|
562
|
-
lines.push(`model requested=${requested}; resolved=${resolved}; status=${evidence.status}; strategy=${strategy}; verified=${verified}`);
|
|
612
|
+
lines.push(`model ${formatBrowserModelSelectionEvidence(evidence, metadata.model)}`);
|
|
563
613
|
}
|
|
564
614
|
for (const warning of browser.warnings ?? []) {
|
|
565
615
|
lines.push(`warning ${warning.code}: ${warning.message}`);
|
|
@@ -821,7 +871,9 @@ export function formatCompletionSummary(metadata, options = {}) {
|
|
|
821
871
|
if (!metadata.usage || metadata.elapsedMs == null) {
|
|
822
872
|
return null;
|
|
823
873
|
}
|
|
824
|
-
const modeLabel = metadata.mode
|
|
874
|
+
const modeLabel = (metadata.mode ?? metadata.options?.mode) === "browser"
|
|
875
|
+
? `${resolveSessionBrowserModelDisplayName(metadata)}[browser]`
|
|
876
|
+
: (metadata.model ?? "n/a");
|
|
825
877
|
const usage = metadata.usage;
|
|
826
878
|
const cost = resolveSessionCost(metadata);
|
|
827
879
|
const tokensDisplay = [
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
export function buildSessionLifecycle({ engine, detached, reattachCommand, }) {
|
|
1
|
+
export function buildSessionLifecycle({ engine, detached, workerPid, reattachCommand, }) {
|
|
2
2
|
return {
|
|
3
3
|
engine,
|
|
4
4
|
execution: detached ? "background" : "foreground",
|
|
5
5
|
attached: !detached,
|
|
6
6
|
detached,
|
|
7
|
+
workerPid,
|
|
7
8
|
reattachCommand,
|
|
8
9
|
};
|
|
9
10
|
}
|