@steipete/oracle 0.18.0 → 0.20.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 +1 -1
- package/dist/bin/oracle-cli.js +76 -76
- package/dist/bin/oracle-mcp.js +0 -0
- package/dist/src/browser/actions/archiveConversation.js +31 -7
- package/dist/src/browser/actions/assistantResponse.js +43 -1
- package/dist/src/browser/actions/attachmentContext.js +239 -0
- package/dist/src/browser/actions/attachmentDataTransfer.js +19 -1
- package/dist/src/browser/actions/attachmentEvidence.js +78 -0
- package/dist/src/browser/actions/attachmentProgress.js +41 -0
- package/dist/src/browser/actions/attachmentPrompt.js +130 -0
- package/dist/src/browser/actions/attachments.js +306 -355
- package/dist/src/browser/actions/deepResearch.js +170 -45
- package/dist/src/browser/actions/modelSelection.js +91 -4
- package/dist/src/browser/actions/navigation.js +1 -1
- package/dist/src/browser/actions/promptComposer.js +364 -186
- package/dist/src/browser/actions/remoteFileTransfer.js +4 -2
- package/dist/src/browser/actions/thinkingStatus.js +2 -5
- package/dist/src/browser/actions/thinkingTime.js +156 -16
- package/dist/src/browser/actions/webSearch.js +96 -0
- package/dist/src/browser/attachRunning.js +46 -2
- package/dist/src/browser/attachmentValidation.js +53 -0
- package/dist/src/browser/cancellation.js +105 -0
- package/dist/src/browser/chatgptImages.js +2 -0
- package/dist/src/browser/chatgptThrottle.js +104 -0
- package/dist/src/browser/chromeLifecycle.js +272 -47
- package/dist/src/browser/config.js +14 -1
- package/dist/src/browser/detect.js +1 -1
- package/dist/src/browser/index.js +525 -274
- package/dist/src/browser/liveTabs.js +3 -4
- package/dist/src/browser/modelDisplay.js +9 -0
- package/dist/src/browser/pageActions.js +2 -2
- package/dist/src/browser/profileState.js +114 -9
- package/dist/src/browser/projectSourcesRunner.js +83 -15
- package/dist/src/browser/prompt.js +272 -113
- package/dist/src/browser/providers/chatgptDomProvider.js +3 -0
- package/dist/src/browser/reattach.js +31 -4
- package/dist/src/browser/recoveryTarget.js +131 -0
- package/dist/src/browser/sessionRunner.js +73 -11
- package/dist/src/browser/tabLeaseRegistry.js +434 -38
- package/dist/src/browser/targetClaim.js +54 -0
- package/dist/src/browser/utils.js +20 -2
- package/dist/src/cli/browserConfig.js +36 -4
- package/dist/src/cli/browserDefaults.js +10 -0
- package/dist/src/cli/browserTabs.js +15 -29
- package/dist/src/cli/detachedSession.js +69 -0
- package/dist/src/cli/dryRun.js +58 -48
- package/dist/src/cli/harvestIntegrity.js +140 -0
- package/dist/src/cli/options.js +15 -0
- package/dist/src/cli/recoveredBrowserHarvest.js +50 -0
- package/dist/src/cli/runOptions.js +19 -4
- package/dist/src/cli/serveBrowserConfig.js +24 -0
- package/dist/src/cli/sessionDisplay.js +13 -7
- package/dist/src/cli/sessionRunner.js +95 -12
- package/dist/src/config.js +1 -0
- package/dist/src/gemini-web/client.js +67 -21
- package/dist/src/gemini-web/executor.js +4 -0
- package/dist/src/gemini-web/http.js +15 -0
- package/dist/src/gemini-web/models.js +15 -11
- package/dist/src/mcp/server.js +11 -14
- package/dist/src/mcp/tools/chatgptImage.js +4 -4
- package/dist/src/mcp/tools/consult.js +86 -24
- package/dist/src/mcp/tools/projectSources.js +4 -6
- package/dist/src/mcp/tools/sessionResources.js +1 -1
- package/dist/src/mcp/tools/sessions.js +2 -2
- package/dist/src/mcp/tools/wait.js +182 -0
- package/dist/src/mcp/types.js +8 -1
- package/dist/src/oracle/config.js +14 -0
- package/dist/src/oracle/errors.js +11 -0
- package/dist/src/oracle/geminiModels.js +1 -0
- package/dist/src/oracle/providerRoutePlan.js +3 -2
- package/dist/src/oracle/run.js +27 -4
- package/dist/src/remote/client.js +73 -6
- package/dist/src/remote/health.js +6 -2
- package/dist/src/remote/runSlots.js +83 -0
- package/dist/src/remote/server.js +346 -71
- package/dist/src/sessionManager.js +36 -1
- 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 +25 -23
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/CodeResources +0 -0
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/MacOS/OracleNotifier +0 -0
- package/dist/bin/oracle.js +0 -683
- package/dist/docs-site/.nojekyll +0 -0
- package/dist/docs-site/CNAME +0 -1
- package/dist/docs-site/RELEASING.html +0 -410
- package/dist/docs-site/agents.html +0 -374
- package/dist/docs-site/anthropic.html +0 -368
- package/dist/docs-site/bridge.html +0 -400
- package/dist/docs-site/browser-mode.html +0 -588
- package/dist/docs-site/chromium-forks.html +0 -347
- package/dist/docs-site/cli-reference.html +0 -346
- package/dist/docs-site/configuration.html +0 -436
- package/dist/docs-site/favicon.svg +0 -14
- package/dist/docs-site/followup.html +0 -368
- package/dist/docs-site/gemini.html +0 -379
- package/dist/docs-site/grok.html +0 -325
- package/dist/docs-site/index.html +0 -360
- package/dist/docs-site/install.html +0 -335
- package/dist/docs-site/linux.html +0 -321
- package/dist/docs-site/llms.txt +0 -43
- package/dist/docs-site/manual-tests.html +0 -595
- package/dist/docs-site/mcp.html +0 -368
- package/dist/docs-site/multimodel.html +0 -364
- package/dist/docs-site/mythical-pro-agents.html +0 -360
- package/dist/docs-site/notifier.html +0 -338
- package/dist/docs-site/openai-endpoints.html +0 -387
- package/dist/docs-site/openrouter.html +0 -344
- package/dist/docs-site/quickstart.html +0 -369
- package/dist/docs-site/refactor/ux.html +0 -532
- package/dist/docs-site/sessions.html +0 -388
- package/dist/docs-site/social-card.png +0 -0
- package/dist/docs-site/social-card.svg +0 -79
- package/dist/docs-site/spec.html +0 -363
- package/dist/docs-site/testing.html +0 -320
- package/dist/docs-site/tui-debug.html +0 -326
- package/dist/docs-site/windows-work.html +0 -323
- package/dist/docs-site/windows.html +0 -320
- 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/types.js +0 -1
- 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/chromeCookies.js +0 -312
- package/dist/src/browser/keytarShim.js +0 -56
- package/dist/src/browser/profileSync.js +0 -141
- package/dist/src/browser/windowsCookies.js +0 -219
package/README.md
CHANGED
|
@@ -82,7 +82,7 @@ oracle --dry-run summary --files-report \
|
|
|
82
82
|
--file "!**/*.test.ts"
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
-
Generated text bundles include stable line numbers so answers can cite `path:line`.
|
|
85
|
+
Generated text bundles include stable line numbers so answers can cite `path:line`. In browser mode, one uploaded text/source file stays native and multiple text/source files are packed into one bundle: flattened text for text-only `auto` uploads, or a ZIP when raw files are present or `--browser-bundle-format zip` is set. Native images and documents remain direct attachments when possible. The [CLI reference](docs/cli-reference.md) lists the file, size, output, and browser controls.
|
|
86
86
|
|
|
87
87
|
## Sessions and follow-ups
|
|
88
88
|
|
package/dist/bin/oracle-cli.js
CHANGED
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import "dotenv/config";
|
|
3
|
-
import { spawn } from "node:child_process";
|
|
4
3
|
import { fileURLToPath } from "node:url";
|
|
5
4
|
import { Command, Option } from "commander";
|
|
6
|
-
// Allow `npx @steipete/oracle oracle-mcp` to resolve the MCP server even though npx runs the default binary.
|
|
7
|
-
if (process.argv[2] === "oracle-mcp") {
|
|
8
|
-
const { startMcpServer } = await import("../src/mcp/server.js");
|
|
9
|
-
await startMcpServer();
|
|
10
|
-
process.exit(0);
|
|
11
|
-
}
|
|
12
5
|
import { resolveEngine, defaultWaitPreference } from "../src/cli/engine.js";
|
|
13
6
|
import { shouldRequirePrompt } from "../src/cli/promptRequirement.js";
|
|
14
7
|
import { resolveDashPrompt } from "../src/cli/stdin.js";
|
|
@@ -20,8 +13,10 @@ import { CHATGPT_URL } from "../src/browser/constants.js";
|
|
|
20
13
|
import { applyHelpStyling } from "../src/cli/help.js";
|
|
21
14
|
import { collectPaths, collectModelList, collectTextValues, parseFloatOption, parseIntOption, parseSearchOption, parseThinkingTimeOption, usesDefaultStatusFilters, resolvePreviewMode, normalizeModelOption, normalizeBaseUrl, resolveApiModel, inferModelFromLabel, parseHeartbeatOption, parseTimeoutOption, parseDurationOption, mergePathLikeOptions, dedupePathInputs, } from "../src/cli/options.js";
|
|
22
15
|
import { copyToClipboard } from "../src/cli/clipboard.js";
|
|
16
|
+
import { isGpt6ProAlias } from "../src/cli/browserConfig.js";
|
|
23
17
|
import { buildMarkdownBundle } from "../src/cli/markdownBundle.js";
|
|
24
18
|
import { shouldDetachSession, stopDetachedWorker } from "../src/cli/detach.js";
|
|
19
|
+
import { launchDetachedSession } from "../src/cli/detachedSession.js";
|
|
25
20
|
import { applyHiddenAliases } from "../src/cli/hiddenAliases.js";
|
|
26
21
|
import { isMediaFile } from "../src/browser/prompt.js";
|
|
27
22
|
import { formatCompactNumber } from "../src/cli/format.js";
|
|
@@ -231,15 +226,8 @@ program
|
|
|
231
226
|
.addOption(new Option("--models <models>", 'Comma-separated API model list to query in parallel (e.g., "gpt-5.5-pro,gemini-3-pro").')
|
|
232
227
|
.argParser(collectModelList)
|
|
233
228
|
.default([]))
|
|
234
|
-
.addOption(new Option("--reasoning-effort <effort>", "Reasoning effort for GPT-5.6 API models.").choices([
|
|
235
|
-
"
|
|
236
|
-
"low",
|
|
237
|
-
"medium",
|
|
238
|
-
"high",
|
|
239
|
-
"xhigh",
|
|
240
|
-
"max",
|
|
241
|
-
]))
|
|
242
|
-
.addOption(new Option("--reasoning-mode <mode>", 'Responses API reasoning execution mode for GPT-5.6 models ("standard" or "pro").').choices(["standard", "pro"]))
|
|
229
|
+
.addOption(new Option("--reasoning-effort <effort>", "Reasoning effort for GPT-6 Astra and GPT-5.6 API models (Astra requires low or higher).").choices(["none", "low", "medium", "high", "xhigh", "max"]))
|
|
230
|
+
.addOption(new Option("--reasoning-mode <mode>", 'Responses API reasoning execution mode for GPT-6 Astra and GPT-5.6 models ("standard" or "pro").').choices(["standard", "pro"]))
|
|
243
231
|
.addOption(new Option("-e, --engine <mode>", "Execution engine (api | browser). Browser engine: GPT models automate ChatGPT; Gemini models use a cookie-based client for gemini.google.com. If omitted, oracle picks api when OPENAI_API_KEY is set, otherwise browser.").choices(["api", "browser"]))
|
|
244
232
|
.addOption(new Option("--mode <mode>", "Alias for --engine (api | browser).")
|
|
245
233
|
.choices(["api", "browser"])
|
|
@@ -283,6 +271,7 @@ program
|
|
|
283
271
|
.option("--render", "Alias for --render-markdown.", false)
|
|
284
272
|
.option("--render-plain", "Render markdown without ANSI/highlighting (use plain text even in a TTY).", false)
|
|
285
273
|
.option("--write-output <path>", "Write only the final assistant message to this file (overwrites; multi-model appends .<model> before the extension).")
|
|
274
|
+
.option("--write-artifacts", "Also export captured browser files beside --write-output without overwriting existing files (browser runs only).", false)
|
|
286
275
|
.option("--allow-partial", "Exit 0 for multi-model runs when at least one model succeeds.", false)
|
|
287
276
|
.addOption(new Option("--partial <mode>", "Multi-model failure policy (fail | ok).")
|
|
288
277
|
.choices(["fail", "ok"])
|
|
@@ -314,6 +303,7 @@ program
|
|
|
314
303
|
.addOption(new Option("--browser-url <url>", `Alias for --chatgpt-url (default ${CHATGPT_URL}).`).hideHelp())
|
|
315
304
|
.addOption(new Option("--browser-timeout <ms|s|m>", "Maximum time to wait for an answer (default 1200s / 20m).").hideHelp())
|
|
316
305
|
.addOption(new Option("--browser-input-timeout <ms|s|m>", "Maximum time to wait for the prompt textarea (default 60s).").hideHelp())
|
|
306
|
+
.addOption(new Option("--browser-approval-wait <duration>", "Wait for each Chrome remote-debugging approval prompt (default 20s; e.g. 5m).").env("ORACLE_BROWSER_APPROVAL_WAIT"))
|
|
317
307
|
.addOption(new Option("--browser-attachment-timeout <ms|s|m>", "Maximum time to wait for attachment upload/readiness before clicking send (default 45s).").hideHelp())
|
|
318
308
|
.addOption(new Option("--browser-recheck-delay <ms|s|m|h>", "After an assistant timeout, wait this long then revisit the conversation to retry capture.").hideHelp())
|
|
319
309
|
.addOption(new Option("--browser-recheck-timeout <ms|s|m|h>", "Time budget for the delayed recheck attempt (default 120s).").hideHelp())
|
|
@@ -343,7 +333,7 @@ program
|
|
|
343
333
|
.addOption(new Option("--browser-thinking-time <level>", "Thinking time intensity for Thinking/Pro models: light, standard, extended, extra-high (Extra High), pro (Pro tier of the active model), heavy, or ChatGPT UI aliases.")
|
|
344
334
|
.argParser(parseThinkingTimeOption)
|
|
345
335
|
.hideHelp())
|
|
346
|
-
.addOption(new Option("--browser-research <mode>", "Browser research mode: deep activates
|
|
336
|
+
.addOption(new Option("--browser-research <mode>", "Browser research mode: search activates Web Search; deep activates Deep Research.").choices(["off", "search", "deep"]))
|
|
347
337
|
.addOption(new Option("--browser-archive <mode>", "Archive completed ChatGPT browser conversations after local artifacts are saved (auto archives successful non-project one-shots only).").choices(["auto", "always", "never"]))
|
|
348
338
|
.addOption(new Option("--browser-follow-up <prompt>", "Submit an additional prompt in the same ChatGPT browser conversation after the initial answer; repeat for multi-turn consults.")
|
|
349
339
|
.argParser(collectTextValues)
|
|
@@ -357,8 +347,8 @@ program
|
|
|
357
347
|
.addOption(new Option("--remote-host <host:port>", "Delegate browser runs to a remote `oracle serve` instance."))
|
|
358
348
|
.addOption(new Option("--remote-token <token>", "Access token for the remote `oracle serve` instance."))
|
|
359
349
|
.addOption(new Option("--browser-inline-files", "Alias for --browser-attachments never (force pasting file contents inline).").default(false))
|
|
360
|
-
.addOption(new Option("--browser-bundle-files", "
|
|
361
|
-
.addOption(new Option("--browser-bundle-format <format>", "Bundle format for browser uploads when files are
|
|
350
|
+
.addOption(new Option("--browser-bundle-files", "Force one browser upload bundle; auto/zip includes all resolved files. Multi-file text/source uploads already bundle by default (flattened text unless ZIP is selected).").default(false))
|
|
351
|
+
.addOption(new Option("--browser-bundle-format <format>", "Bundle format for browser uploads: auto (flattened text for text-only, ZIP when raw files are present), text, or zip.")
|
|
362
352
|
.choices(["auto", "text", "zip"])
|
|
363
353
|
.default("auto"))
|
|
364
354
|
.addOption(new Option("--youtube <url>", "YouTube video URL to analyze (Gemini web/cookie mode only; uses your signed-in Chrome cookies for gemini.google.com)."))
|
|
@@ -367,6 +357,7 @@ program
|
|
|
367
357
|
.addOption(new Option("--output <file>", "Output file path for image operations."))
|
|
368
358
|
.addOption(new Option("--aspect <ratio>", "Aspect ratio for image generation: 16:9, 1:1, 4:3, 3:4 (Gemini web/cookie mode only)."))
|
|
369
359
|
.addOption(new Option("--gemini-show-thoughts", "Display Gemini thinking process (Gemini web/cookie mode only).").default(false))
|
|
360
|
+
.option("--no-gemini-fallback", "Fail if the requested Gemini web model is unavailable instead of using Flash-Lite.")
|
|
370
361
|
.option("--retain-hours <hours>", "Prune stored sessions older than this many hours before running (set 0 to disable).", parseFloatOption)
|
|
371
362
|
.option("--force", "Force start a new session even if an identical prompt is already running.", false)
|
|
372
363
|
.option("--debug-help", "Show the advanced/debug option set and exit.", false)
|
|
@@ -392,15 +383,26 @@ program
|
|
|
392
383
|
.option("--host <address>", "Interface to bind (default 0.0.0.0).")
|
|
393
384
|
.option("--port <number>", "Port to listen on (default random).", parseIntOption)
|
|
394
385
|
.option("--token <value>", "Access token clients must provide (random if omitted).")
|
|
386
|
+
.option("--max-concurrent-runs <count>", "Opt into concurrent runs and FIFO queueing; clamped to the host browser tab cap (default remains single-flight HTTP 409).")
|
|
387
|
+
.option("--max-queued-runs <count>", "Waiting requests in opt-in queue mode (default 8; 0 disables waiting).")
|
|
395
388
|
.option("--manual-login", "Use a dedicated Chrome profile for manual login (recommended when cookie sync is unavailable).", false)
|
|
396
389
|
.option("--manual-login-profile-dir <path>", "Chrome profile directory for manual login (default ~/.oracle/browser-profile).")
|
|
397
390
|
.option("--browser-cookie-sync", "Copy cookies from this host's live Chrome profile instead of using the dedicated profile.", false)
|
|
398
391
|
.action(async (commandOptions) => {
|
|
399
392
|
const { serveRemote } = await import("../src/remote/server.js");
|
|
393
|
+
const { buildServeBrowserConfig } = await import("../src/cli/serveBrowserConfig.js");
|
|
394
|
+
const { config } = await loadUserConfig();
|
|
400
395
|
await serveRemote({
|
|
396
|
+
browserConfig: buildServeBrowserConfig(program.opts(), config),
|
|
401
397
|
host: commandOptions.host,
|
|
402
398
|
port: commandOptions.port,
|
|
403
399
|
token: commandOptions.token,
|
|
400
|
+
maxConcurrentRuns: commandOptions.maxConcurrentRuns === undefined
|
|
401
|
+
? undefined
|
|
402
|
+
: Number(commandOptions.maxConcurrentRuns),
|
|
403
|
+
maxQueuedRuns: commandOptions.maxQueuedRuns === undefined
|
|
404
|
+
? undefined
|
|
405
|
+
: Number(commandOptions.maxQueuedRuns),
|
|
404
406
|
manualLoginDefault: commandOptions.manualLogin,
|
|
405
407
|
manualLoginProfileDir: commandOptions.manualLoginProfileDir,
|
|
406
408
|
cookieSyncDefault: commandOptions.browserCookieSync,
|
|
@@ -713,6 +715,7 @@ function buildRunOptions(options, overrides = {}) {
|
|
|
713
715
|
background: overrides.background ?? undefined,
|
|
714
716
|
renderPlain: overrides.renderPlain ?? options.renderPlain ?? false,
|
|
715
717
|
writeOutputPath: overrides.writeOutputPath ?? options.writeOutputPath,
|
|
718
|
+
writeArtifacts: overrides.writeArtifacts ?? options.writeArtifacts ?? false,
|
|
716
719
|
};
|
|
717
720
|
}
|
|
718
721
|
function resolveApiProviderMode(options) {
|
|
@@ -952,6 +955,7 @@ function buildRunOptionsFromMetadata(metadata) {
|
|
|
952
955
|
background: stored.background,
|
|
953
956
|
renderPlain: stored.renderPlain,
|
|
954
957
|
writeOutputPath: stored.writeOutputPath,
|
|
958
|
+
writeArtifacts: stored.writeArtifacts,
|
|
955
959
|
};
|
|
956
960
|
}
|
|
957
961
|
function getSessionMode(metadata) {
|
|
@@ -1054,9 +1058,13 @@ async function runRootCommand(options) {
|
|
|
1054
1058
|
options.baseUrl = userConfig.apiBaseUrl;
|
|
1055
1059
|
}
|
|
1056
1060
|
const providerMode = resolveApiProviderMode(options);
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1061
|
+
// Engine discovery must not apply API-only validation to browser aliases.
|
|
1062
|
+
const engineModelInputs = multiModelProvided
|
|
1063
|
+
? options.models
|
|
1064
|
+
: [normalizeModelOption(options.model) || DEFAULT_MODEL];
|
|
1065
|
+
const engineModels = Array.from(new Set(engineModelInputs.map((entry) => isGpt6ProAlias(entry) && !options.route && !options.preflight
|
|
1066
|
+
? "gpt-6-pro"
|
|
1067
|
+
: resolveApiModel(entry))));
|
|
1060
1068
|
if (options.route || options.preflight) {
|
|
1061
1069
|
const routeAzureEndpoint = firstNonEmpty(options.azureEndpoint, process.env.AZURE_OPENAI_ENDPOINT, userConfig.azure?.endpoint);
|
|
1062
1070
|
const configuredAzureForRoute = routeAzureEndpoint
|
|
@@ -1080,8 +1088,10 @@ async function runRootCommand(options) {
|
|
|
1080
1088
|
return;
|
|
1081
1089
|
}
|
|
1082
1090
|
const retentionHours = typeof options.retainHours === "number" ? options.retainHours : undefined;
|
|
1083
|
-
|
|
1084
|
-
|
|
1091
|
+
if (!previewMode) {
|
|
1092
|
+
await sessionStore.ensureStorage();
|
|
1093
|
+
await pruneOldSessions(retentionHours, (message) => console.log(chalk.dim(message)));
|
|
1094
|
+
}
|
|
1085
1095
|
if (providerMode === "openai") {
|
|
1086
1096
|
if (hasExplicitAzureOption(optionUsesDefault)) {
|
|
1087
1097
|
throw new Error("--provider openai/--no-azure cannot be combined with Azure options.");
|
|
@@ -1316,6 +1326,12 @@ async function runRootCommand(options) {
|
|
|
1316
1326
|
}
|
|
1317
1327
|
}
|
|
1318
1328
|
const activeModel = resolvedOptions.model;
|
|
1329
|
+
if (options.writeArtifacts && engine !== "browser") {
|
|
1330
|
+
throw new Error("--write-artifacts requires --engine browser.");
|
|
1331
|
+
}
|
|
1332
|
+
if (options.writeArtifacts && !resolvedOptions.writeOutputPath) {
|
|
1333
|
+
throw new Error("--write-artifacts requires --write-output <path>.");
|
|
1334
|
+
}
|
|
1319
1335
|
if (options.reasoningMode && engine !== "api") {
|
|
1320
1336
|
throw new Error("--reasoning-mode requires --engine api.");
|
|
1321
1337
|
}
|
|
@@ -1447,6 +1463,7 @@ async function runRootCommand(options) {
|
|
|
1447
1463
|
outputPath: options.output,
|
|
1448
1464
|
aspectRatio: options.aspect,
|
|
1449
1465
|
showThoughts: options.geminiShowThoughts,
|
|
1466
|
+
allowModelFallback: options.geminiFallback,
|
|
1450
1467
|
}),
|
|
1451
1468
|
};
|
|
1452
1469
|
console.log(chalk.dim("Using Gemini web client for browser automation"));
|
|
@@ -1516,6 +1533,7 @@ async function runRootCommand(options) {
|
|
|
1516
1533
|
outputPath: options.output,
|
|
1517
1534
|
aspectRatio: options.aspect,
|
|
1518
1535
|
geminiShowThoughts: options.geminiShowThoughts,
|
|
1536
|
+
geminiAllowModelFallback: options.geminiFallback,
|
|
1519
1537
|
}, process.cwd(), notifications);
|
|
1520
1538
|
const liveRunOptions = {
|
|
1521
1539
|
...baseRunOptions,
|
|
@@ -1539,14 +1557,19 @@ async function runRootCommand(options) {
|
|
|
1539
1557
|
});
|
|
1540
1558
|
const workerPid = !detachAllowed
|
|
1541
1559
|
? undefined
|
|
1542
|
-
: await launchDetachedSession(
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1560
|
+
: await launchDetachedSession({
|
|
1561
|
+
sessionId: sessionMeta.id,
|
|
1562
|
+
cliEntrypoint: CLI_ENTRYPOINT,
|
|
1563
|
+
env: buildDetachedPerfTraceEnv(process.env, perfTraceArgs.value, sessionMeta.id),
|
|
1564
|
+
prepare: async (pid) => {
|
|
1565
|
+
lifecycle = buildSessionLifecycle({
|
|
1566
|
+
engine,
|
|
1567
|
+
detached: true,
|
|
1568
|
+
workerPid: pid,
|
|
1569
|
+
reattachCommand: `oracle session ${sessionMeta.id}`,
|
|
1570
|
+
});
|
|
1571
|
+
await sessionStore.updateSession(sessionMeta.id, { lifecycle });
|
|
1572
|
+
},
|
|
1550
1573
|
}).catch((error) => {
|
|
1551
1574
|
const message = error instanceof Error ? error.message : String(error);
|
|
1552
1575
|
console.log(chalk.yellow(`Unable to detach session runner (${message}). Running inline...`));
|
|
@@ -1634,42 +1657,6 @@ async function runInteractiveSession(sessionMeta, runOptions, mode, browserConfi
|
|
|
1634
1657
|
stream.end();
|
|
1635
1658
|
}
|
|
1636
1659
|
}
|
|
1637
|
-
async function launchDetachedSession(sessionId, prepare) {
|
|
1638
|
-
return new Promise((resolve, reject) => {
|
|
1639
|
-
try {
|
|
1640
|
-
const args = ["--", CLI_ENTRYPOINT, "--exec-session", sessionId];
|
|
1641
|
-
const env = {
|
|
1642
|
-
...buildDetachedPerfTraceEnv(process.env, perfTraceArgs.value, sessionId),
|
|
1643
|
-
ORACLE_DETACHED_START_GATE: "1",
|
|
1644
|
-
};
|
|
1645
|
-
const child = spawn(process.execPath, args, {
|
|
1646
|
-
detached: true,
|
|
1647
|
-
stdio: ["pipe", "ignore", "ignore"],
|
|
1648
|
-
env,
|
|
1649
|
-
});
|
|
1650
|
-
child.once("error", reject);
|
|
1651
|
-
child.once("spawn", async () => {
|
|
1652
|
-
if (child.pid === undefined) {
|
|
1653
|
-
reject(new Error("Detached session worker started without a process ID."));
|
|
1654
|
-
return;
|
|
1655
|
-
}
|
|
1656
|
-
try {
|
|
1657
|
-
await prepare(child.pid);
|
|
1658
|
-
child.stdin.end("ready\n");
|
|
1659
|
-
child.unref();
|
|
1660
|
-
resolve(child.pid);
|
|
1661
|
-
}
|
|
1662
|
-
catch (error) {
|
|
1663
|
-
child.kill();
|
|
1664
|
-
reject(error);
|
|
1665
|
-
}
|
|
1666
|
-
});
|
|
1667
|
-
}
|
|
1668
|
-
catch (error) {
|
|
1669
|
-
reject(error);
|
|
1670
|
-
}
|
|
1671
|
-
});
|
|
1672
|
-
}
|
|
1673
1660
|
async function waitForDetachedStartGate() {
|
|
1674
1661
|
if (process.env.ORACLE_DETACHED_START_GATE !== "1") {
|
|
1675
1662
|
return;
|
|
@@ -1794,6 +1781,7 @@ async function restartSession(sessionId, options) {
|
|
|
1794
1781
|
outputPath: storedOptions.outputPath,
|
|
1795
1782
|
aspectRatio: storedOptions.aspectRatio,
|
|
1796
1783
|
showThoughts: storedOptions.geminiShowThoughts,
|
|
1784
|
+
allowModelFallback: storedOptions.geminiAllowModelFallback,
|
|
1797
1785
|
}),
|
|
1798
1786
|
};
|
|
1799
1787
|
console.log(chalk.dim("Using Gemini web client for browser automation"));
|
|
@@ -1820,6 +1808,7 @@ async function restartSession(sessionId, options) {
|
|
|
1820
1808
|
outputPath: storedOptions.outputPath,
|
|
1821
1809
|
aspectRatio: storedOptions.aspectRatio,
|
|
1822
1810
|
geminiShowThoughts: storedOptions.geminiShowThoughts,
|
|
1811
|
+
geminiAllowModelFallback: storedOptions.geminiAllowModelFallback,
|
|
1823
1812
|
}, cwd, notifications, sessionId);
|
|
1824
1813
|
const liveRunOptions = {
|
|
1825
1814
|
...runOptions,
|
|
@@ -1843,14 +1832,19 @@ async function restartSession(sessionId, options) {
|
|
|
1843
1832
|
});
|
|
1844
1833
|
const workerPid = !detachAllowed
|
|
1845
1834
|
? undefined
|
|
1846
|
-
: await launchDetachedSession(
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1835
|
+
: await launchDetachedSession({
|
|
1836
|
+
sessionId: sessionMeta.id,
|
|
1837
|
+
cliEntrypoint: CLI_ENTRYPOINT,
|
|
1838
|
+
env: buildDetachedPerfTraceEnv(process.env, perfTraceArgs.value, sessionMeta.id),
|
|
1839
|
+
prepare: async (pid) => {
|
|
1840
|
+
lifecycle = buildSessionLifecycle({
|
|
1841
|
+
engine,
|
|
1842
|
+
detached: true,
|
|
1843
|
+
workerPid: pid,
|
|
1844
|
+
reattachCommand: `oracle session ${sessionMeta.id}`,
|
|
1845
|
+
});
|
|
1846
|
+
await sessionStore.updateSession(sessionMeta.id, { lifecycle });
|
|
1847
|
+
},
|
|
1854
1848
|
}).catch((error) => {
|
|
1855
1849
|
const message = error instanceof Error ? error.message : String(error);
|
|
1856
1850
|
console.log(chalk.yellow(`Unable to detach session runner (${message}). Running inline...`));
|
|
@@ -2038,6 +2032,12 @@ program.action(async function () {
|
|
|
2038
2032
|
await runRootCommand(options);
|
|
2039
2033
|
});
|
|
2040
2034
|
async function main() {
|
|
2035
|
+
// npx runs the default binary; let the MCP transport own the alias lifetime.
|
|
2036
|
+
if (process.argv[2] === "oracle-mcp") {
|
|
2037
|
+
const { startMcpServer } = await import("../src/mcp/server.js");
|
|
2038
|
+
await startMcpServer();
|
|
2039
|
+
return;
|
|
2040
|
+
}
|
|
2041
2041
|
if (perfTraceArgs.error) {
|
|
2042
2042
|
console.error(`error: ${perfTraceArgs.error}`);
|
|
2043
2043
|
console.error("(use --help for usage)");
|
package/dist/bin/oracle-mcp.js
CHANGED
|
File without changes
|
|
@@ -124,7 +124,9 @@ function buildArchiveConversationExpression() {
|
|
|
124
124
|
label.includes('conversation options') ||
|
|
125
125
|
label.includes('open menu') ||
|
|
126
126
|
label.includes('więcej') ||
|
|
127
|
-
label.includes('opcje')
|
|
127
|
+
label.includes('opcje') ||
|
|
128
|
+
label === 'その他' ||
|
|
129
|
+
label.includes('会話オプション')
|
|
128
130
|
);
|
|
129
131
|
const headerCandidates = labelled
|
|
130
132
|
.filter(({ rect }) => rect.top < 180 && rect.right > window.innerWidth - 420)
|
|
@@ -144,8 +146,17 @@ function buildArchiveConversationExpression() {
|
|
|
144
146
|
return candidates.find((element) => {
|
|
145
147
|
const label = labelFor(element);
|
|
146
148
|
if (!label) return false;
|
|
147
|
-
if (
|
|
148
|
-
|
|
149
|
+
if (
|
|
150
|
+
label.includes('unarchive') ||
|
|
151
|
+
label.includes('restore') ||
|
|
152
|
+
label.includes('アーカイブを解除')
|
|
153
|
+
) return false;
|
|
154
|
+
return (
|
|
155
|
+
label.includes('archive') ||
|
|
156
|
+
label.includes('archiwizuj') ||
|
|
157
|
+
label === 'アーカイブ' ||
|
|
158
|
+
label.includes('アーカイブする')
|
|
159
|
+
);
|
|
149
160
|
}) ?? null;
|
|
150
161
|
};
|
|
151
162
|
const findArchiveConfirmationButton = () => {
|
|
@@ -154,8 +165,18 @@ function buildArchiveConversationExpression() {
|
|
|
154
165
|
return candidates.find((element) => {
|
|
155
166
|
const label = labelFor(element);
|
|
156
167
|
if (!label) return false;
|
|
157
|
-
if (
|
|
158
|
-
|
|
168
|
+
if (
|
|
169
|
+
label.includes('unarchive') ||
|
|
170
|
+
label.includes('restore') ||
|
|
171
|
+
label.includes('アーカイブを解除')
|
|
172
|
+
) return false;
|
|
173
|
+
return (
|
|
174
|
+
label === 'archive' ||
|
|
175
|
+
label === 'archiwizuj' ||
|
|
176
|
+
label.includes('archive conversation') ||
|
|
177
|
+
label === 'アーカイブ' ||
|
|
178
|
+
label.includes('アーカイブする')
|
|
179
|
+
);
|
|
159
180
|
}) ?? null;
|
|
160
181
|
};
|
|
161
182
|
const hasUnarchiveMenuItem = () => {
|
|
@@ -166,7 +187,8 @@ function buildArchiveConversationExpression() {
|
|
|
166
187
|
label.includes('unarchive') ||
|
|
167
188
|
label.includes('restore') ||
|
|
168
189
|
label.includes('przywróć') ||
|
|
169
|
-
label.includes('przywroc')
|
|
190
|
+
label.includes('przywroc') ||
|
|
191
|
+
label.includes('アーカイブを解除')
|
|
170
192
|
);
|
|
171
193
|
});
|
|
172
194
|
};
|
|
@@ -180,7 +202,9 @@ function buildArchiveConversationExpression() {
|
|
|
180
202
|
visibleText.includes('conversation archived') ||
|
|
181
203
|
visibleText.includes('chat archived') ||
|
|
182
204
|
visibleText.includes('zarchiwizowano') ||
|
|
183
|
-
visibleText.includes('archiwum')
|
|
205
|
+
visibleText.includes('archiwum') ||
|
|
206
|
+
visibleText.includes('アーカイブしました') ||
|
|
207
|
+
visibleText.includes('アーカイブされました')
|
|
184
208
|
);
|
|
185
209
|
};
|
|
186
210
|
const waitForArchiveConfirmation = async () => {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { ANSWER_SELECTORS, ASSISTANT_ROLE_SELECTOR, CONVERSATION_TURN_SELECTOR, COPY_BUTTON_SELECTOR, FINISHED_ACTIONS_SELECTOR, STOP_BUTTON_SELECTORS, } from "../constants.js";
|
|
2
2
|
import { buildConversationTurnListExpression } from "../conversationTurns.js";
|
|
3
|
-
import { buildThinkingActivePredicateJs, readThinkingActivity } from "./thinkingStatus.js";
|
|
3
|
+
import { buildThinkingActivePredicateJs, buildThinkingActivityDetailsPredicateJs, readThinkingActivity, } from "./thinkingStatus.js";
|
|
4
4
|
import { delay } from "../utils.js";
|
|
5
5
|
import { logDomFailure, logConversationSnapshot, buildConversationDebugExpression, } from "../domDebug.js";
|
|
6
6
|
import { buildClickDispatcher } from "./domEvents.js";
|
|
7
|
+
import { BrowserAutomationError } from "../../oracle/errors.js";
|
|
7
8
|
const ASSISTANT_POLL_TIMEOUT_ERROR = "assistant-response-watchdog-timeout";
|
|
8
9
|
const STOP_CONTROL_SELECTOR = STOP_BUTTON_SELECTORS.join(", ");
|
|
9
10
|
// Still used by the in-page settle heuristic's length buckets (see buildResponseObserverExpression).
|
|
@@ -148,6 +149,14 @@ export function isAnswerNowPlaceholderText(value) {
|
|
|
148
149
|
}
|
|
149
150
|
return sawGate && sawOwner;
|
|
150
151
|
}
|
|
152
|
+
export function isRetryAssistantUiErrorText(value, retryVisible) {
|
|
153
|
+
if (!retryVisible || typeof value !== "string")
|
|
154
|
+
return false;
|
|
155
|
+
const text = value.toLowerCase().replace(/\s+/g, " ").trim();
|
|
156
|
+
return (text.includes("something went wrong") ||
|
|
157
|
+
text.includes("failed to generate") ||
|
|
158
|
+
text.includes("try again later"));
|
|
159
|
+
}
|
|
151
160
|
// Exported: the two page expressions below and the tests all consume this one builder,
|
|
152
161
|
// so the predicate cannot drift between the node side and the renderer.
|
|
153
162
|
export function buildAnswerNowPlaceholderPredicateJs(fnName) {
|
|
@@ -227,6 +236,8 @@ export async function waitForAssistantResponse(Runtime, timeoutMs, logger, minTu
|
|
|
227
236
|
throw error;
|
|
228
237
|
}
|
|
229
238
|
else if (source === "poll") {
|
|
239
|
+
evaluationPromise.catch(() => undefined);
|
|
240
|
+
await terminateRuntimeExecution(Runtime);
|
|
230
241
|
throw error;
|
|
231
242
|
}
|
|
232
243
|
else if (source === "evaluation") {
|
|
@@ -399,6 +410,7 @@ async function parseAssistantEvaluationResult(_Runtime, evaluation, _logger) {
|
|
|
399
410
|
result.value &&
|
|
400
411
|
typeof result.value === "object" &&
|
|
401
412
|
"text" in result.value) {
|
|
413
|
+
throwIfAssistantUiError(result.value);
|
|
402
414
|
const html = typeof result.value.html === "string"
|
|
403
415
|
? (result.value.html ?? undefined)
|
|
404
416
|
: undefined;
|
|
@@ -631,6 +643,7 @@ export function hasScopedCompletionProof(meta) {
|
|
|
631
643
|
}
|
|
632
644
|
export const buildCompletionVisibilityExpressionForTest = buildCompletionVisibilityExpression;
|
|
633
645
|
function normalizeAssistantSnapshot(snapshot) {
|
|
646
|
+
throwIfAssistantUiError(snapshot);
|
|
634
647
|
const text = snapshot?.text ? cleanAssistantText(snapshot.text) : "";
|
|
635
648
|
if (!text.trim()) {
|
|
636
649
|
return null;
|
|
@@ -655,6 +668,19 @@ function normalizeAssistantSnapshot(snapshot) {
|
|
|
655
668
|
},
|
|
656
669
|
};
|
|
657
670
|
}
|
|
671
|
+
export function throwIfAssistantUiError(snapshot) {
|
|
672
|
+
if (snapshot?.uiError !== "temporary_unavailable")
|
|
673
|
+
return;
|
|
674
|
+
throw new BrowserAutomationError("ChatGPT could not generate the submitted assistant turn and offered Retry.", {
|
|
675
|
+
stage: "assistant-ui-error",
|
|
676
|
+
code: "chatgpt-ui-warning",
|
|
677
|
+
uiWarning: {
|
|
678
|
+
type: "temporary_unavailable",
|
|
679
|
+
message: "ChatGPT offered Retry for the submitted assistant turn.",
|
|
680
|
+
source: "assistant-turn",
|
|
681
|
+
},
|
|
682
|
+
});
|
|
683
|
+
}
|
|
658
684
|
function isGeneratedImageAssistantAnswer(answer) {
|
|
659
685
|
return Boolean(answer?.html?.includes("/backend-api/estuary/content?id=file_"));
|
|
660
686
|
}
|
|
@@ -949,6 +975,8 @@ function buildAssistantExtractor(functionName) {
|
|
|
949
975
|
const assistantLiteral = JSON.stringify(ASSISTANT_ROLE_SELECTOR);
|
|
950
976
|
return `const ${functionName} = () => {
|
|
951
977
|
${buildClickDispatcher()}
|
|
978
|
+
${buildThinkingActivityDetailsPredicateJs("readRetryThinkingActivity")}
|
|
979
|
+
const isRetryAssistantUiError = ${isRetryAssistantUiErrorText.toString()};
|
|
952
980
|
const ASSISTANT_SELECTOR = ${assistantLiteral};
|
|
953
981
|
const isAssistantTurn = (node) => {
|
|
954
982
|
if (!(node instanceof HTMLElement)) return false;
|
|
@@ -1014,6 +1042,20 @@ function buildAssistantExtractor(functionName) {
|
|
|
1014
1042
|
String(img?.src || '').includes('/backend-api/estuary/content?id=file_')
|
|
1015
1043
|
);
|
|
1016
1044
|
const normalizedText = String(text || '').toLowerCase().replace(/\\s+/g, ' ').trim();
|
|
1045
|
+
const retryVisible = Array.from(turn.querySelectorAll('button, [role="button"]')).some((button) => {
|
|
1046
|
+
const label = String(button.innerText || button.textContent || button.getAttribute?.('aria-label') || '')
|
|
1047
|
+
.toLowerCase()
|
|
1048
|
+
.replace(/\\s+/g, ' ')
|
|
1049
|
+
.trim();
|
|
1050
|
+
if (label !== 'retry' || !(button instanceof HTMLElement)) return false;
|
|
1051
|
+
const rect = button.getBoundingClientRect();
|
|
1052
|
+
const style = window.getComputedStyle(button);
|
|
1053
|
+
return rect.width > 0 && rect.height > 0 && style.display !== 'none' && style.visibility !== 'hidden' &&
|
|
1054
|
+
!(style.opacity !== '' && Number(style.opacity) === 0);
|
|
1055
|
+
});
|
|
1056
|
+
if (isRetryAssistantUiError(text, retryVisible) && !readRetryThinkingActivity().strong) {
|
|
1057
|
+
return { text, html, messageId, turnId, turnIndex: index, uiError: 'temporary_unavailable' };
|
|
1058
|
+
}
|
|
1017
1059
|
const imageOnlyChrome =
|
|
1018
1060
|
!normalizedText ||
|
|
1019
1061
|
normalizedText === 'edit' ||
|