@steipete/oracle 0.17.3 → 0.19.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 +75 -64
- 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 +2 -1
- package/dist/src/browser/actions/modelSelection.js +13 -3
- package/dist/src/browser/actions/navigation.js +1 -1
- package/dist/src/browser/actions/promptComposer.js +361 -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 +267 -15
- 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 +267 -43
- package/dist/src/browser/config.js +15 -3
- package/dist/src/browser/detect.js +1 -1
- package/dist/src/browser/index.js +447 -263
- package/dist/src/browser/modelDisplay.js +9 -0
- package/dist/src/browser/pageActions.js +2 -2
- package/dist/src/browser/policies.js +6 -2
- package/dist/src/browser/profileState.js +114 -9
- package/dist/src/browser/projectSourcesRunner.js +88 -17
- package/dist/src/browser/prompt.js +272 -113
- package/dist/src/browser/providers/chatgptDomProvider.js +2 -0
- package/dist/src/browser/reattach.js +14 -4
- package/dist/src/browser/sessionRunner.js +71 -11
- package/dist/src/browser/tabLeaseRegistry.js +414 -38
- package/dist/src/browser/utils.js +20 -2
- package/dist/src/cli/browserConfig.js +40 -15
- package/dist/src/cli/browserDefaults.js +13 -0
- package/dist/src/cli/browserTabs.js +12 -29
- package/dist/src/cli/detachedSession.js +69 -0
- package/dist/src/cli/dryRun.js +58 -47
- package/dist/src/cli/harvestIntegrity.js +140 -0
- package/dist/src/cli/projectSources.js +5 -3
- package/dist/src/cli/serveBrowserConfig.js +24 -0
- package/dist/src/cli/sessionDisplay.js +9 -2
- package/dist/src/cli/sessionRunner.js +91 -7
- 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 +97 -26
- 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 +7 -0
- package/dist/src/oracle/errors.js +11 -0
- package/dist/src/oracle/providerRoutePlan.js +3 -2
- package/dist/src/remote/client.js +70 -6
- package/dist/src/remote/health.js +6 -2
- package/dist/src/remote/runSlots.js +83 -0
- package/dist/src/remote/server.js +351 -72
- 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";
|
|
@@ -22,6 +15,7 @@ import { collectPaths, collectModelList, collectTextValues, parseFloatOption, pa
|
|
|
22
15
|
import { copyToClipboard } from "../src/cli/clipboard.js";
|
|
23
16
|
import { buildMarkdownBundle } from "../src/cli/markdownBundle.js";
|
|
24
17
|
import { shouldDetachSession, stopDetachedWorker } from "../src/cli/detach.js";
|
|
18
|
+
import { launchDetachedSession } from "../src/cli/detachedSession.js";
|
|
25
19
|
import { applyHiddenAliases } from "../src/cli/hiddenAliases.js";
|
|
26
20
|
import { isMediaFile } from "../src/browser/prompt.js";
|
|
27
21
|
import { formatCompactNumber } from "../src/cli/format.js";
|
|
@@ -227,7 +221,7 @@ program
|
|
|
227
221
|
.addOption(new Option("--copy-markdown", "Copy the assembled markdown bundle to the clipboard; pair with --render to print it too.").default(false))
|
|
228
222
|
.addOption(new Option("--copy").hideHelp().default(false))
|
|
229
223
|
.option("-s, --slug <words>", "Custom session slug (3-5 words).")
|
|
230
|
-
.option("-m, --model <model>", "Model to target (gpt-5.5-pro default). GPT-5.6 aliases gpt-5.6 and gpt-5.6-sol work with the OpenAI API or ChatGPT browser.
|
|
224
|
+
.option("-m, --model <model>", "Model to target (gpt-5.5-pro default). GPT-5.6 aliases gpt-5.6 and gpt-5.6-sol work with the OpenAI API or ChatGPT browser. In browser mode, generic Pro aliases follow the current GPT-5.6 Sol target; use explicit gpt-5.5-pro to pin GPT-5.5. Retired GPT-5.2 base/Instant/Thinking aliases are API-only. Other API targets include gpt-5.1-codex, gpt-5.2, gpt-5.2-instant, Gemini, Claude, and custom model IDs.", normalizeModelOption)
|
|
231
225
|
.addOption(new Option("--models <models>", 'Comma-separated API model list to query in parallel (e.g., "gpt-5.5-pro,gemini-3-pro").')
|
|
232
226
|
.argParser(collectModelList)
|
|
233
227
|
.default([]))
|
|
@@ -283,6 +277,7 @@ program
|
|
|
283
277
|
.option("--render", "Alias for --render-markdown.", false)
|
|
284
278
|
.option("--render-plain", "Render markdown without ANSI/highlighting (use plain text even in a TTY).", false)
|
|
285
279
|
.option("--write-output <path>", "Write only the final assistant message to this file (overwrites; multi-model appends .<model> before the extension).")
|
|
280
|
+
.option("--write-artifacts", "Also export captured browser files beside --write-output without overwriting existing files (browser runs only).", false)
|
|
286
281
|
.option("--allow-partial", "Exit 0 for multi-model runs when at least one model succeeds.", false)
|
|
287
282
|
.addOption(new Option("--partial <mode>", "Multi-model failure policy (fail | ok).")
|
|
288
283
|
.choices(["fail", "ok"])
|
|
@@ -314,6 +309,7 @@ program
|
|
|
314
309
|
.addOption(new Option("--browser-url <url>", `Alias for --chatgpt-url (default ${CHATGPT_URL}).`).hideHelp())
|
|
315
310
|
.addOption(new Option("--browser-timeout <ms|s|m>", "Maximum time to wait for an answer (default 1200s / 20m).").hideHelp())
|
|
316
311
|
.addOption(new Option("--browser-input-timeout <ms|s|m>", "Maximum time to wait for the prompt textarea (default 60s).").hideHelp())
|
|
312
|
+
.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
313
|
.addOption(new Option("--browser-attachment-timeout <ms|s|m>", "Maximum time to wait for attachment upload/readiness before clicking send (default 45s).").hideHelp())
|
|
318
314
|
.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
315
|
.addOption(new Option("--browser-recheck-timeout <ms|s|m|h>", "Time budget for the delayed recheck attempt (default 120s).").hideHelp())
|
|
@@ -331,6 +327,7 @@ program
|
|
|
331
327
|
.addOption(new Option("--browser-cookie-names <names>", "Comma-separated cookie allowlist for sync.").hideHelp())
|
|
332
328
|
.addOption(new Option("--browser-inline-cookies <jsonOrBase64>", "Inline cookies payload (JSON array or base64-encoded JSON).").hideHelp())
|
|
333
329
|
.addOption(new Option("--browser-inline-cookies-file <path>", "Load inline cookies from file (JSON or base64 JSON).").hideHelp())
|
|
330
|
+
.addOption(new Option("--browser-cookie-sync", "Copy cookies from live Chrome (opt-in; token rotation may invalidate that session)."))
|
|
334
331
|
.addOption(new Option("--browser-no-cookie-sync", "Skip copying cookies from Chrome.").hideHelp())
|
|
335
332
|
.addOption(new Option("--browser-manual-login", "Skip cookie copy; reuse a persistent automation profile and wait for manual ChatGPT login.").hideHelp())
|
|
336
333
|
.addOption(new Option("--browser-manual-login-profile-dir <path>", "Persistent Chrome profile directory for manual-login browser runs.").hideHelp())
|
|
@@ -356,8 +353,8 @@ program
|
|
|
356
353
|
.addOption(new Option("--remote-host <host:port>", "Delegate browser runs to a remote `oracle serve` instance."))
|
|
357
354
|
.addOption(new Option("--remote-token <token>", "Access token for the remote `oracle serve` instance."))
|
|
358
355
|
.addOption(new Option("--browser-inline-files", "Alias for --browser-attachments never (force pasting file contents inline).").default(false))
|
|
359
|
-
.addOption(new Option("--browser-bundle-files", "
|
|
360
|
-
.addOption(new Option("--browser-bundle-format <format>", "Bundle format for browser uploads when files are
|
|
356
|
+
.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))
|
|
357
|
+
.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.")
|
|
361
358
|
.choices(["auto", "text", "zip"])
|
|
362
359
|
.default("auto"))
|
|
363
360
|
.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)."))
|
|
@@ -366,6 +363,7 @@ program
|
|
|
366
363
|
.addOption(new Option("--output <file>", "Output file path for image operations."))
|
|
367
364
|
.addOption(new Option("--aspect <ratio>", "Aspect ratio for image generation: 16:9, 1:1, 4:3, 3:4 (Gemini web/cookie mode only)."))
|
|
368
365
|
.addOption(new Option("--gemini-show-thoughts", "Display Gemini thinking process (Gemini web/cookie mode only).").default(false))
|
|
366
|
+
.option("--no-gemini-fallback", "Fail if the requested Gemini web model is unavailable instead of using Flash-Lite.")
|
|
369
367
|
.option("--retain-hours <hours>", "Prune stored sessions older than this many hours before running (set 0 to disable).", parseFloatOption)
|
|
370
368
|
.option("--force", "Force start a new session even if an identical prompt is already running.", false)
|
|
371
369
|
.option("--debug-help", "Show the advanced/debug option set and exit.", false)
|
|
@@ -391,16 +389,29 @@ program
|
|
|
391
389
|
.option("--host <address>", "Interface to bind (default 0.0.0.0).")
|
|
392
390
|
.option("--port <number>", "Port to listen on (default random).", parseIntOption)
|
|
393
391
|
.option("--token <value>", "Access token clients must provide (random if omitted).")
|
|
392
|
+
.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).")
|
|
393
|
+
.option("--max-queued-runs <count>", "Waiting requests in opt-in queue mode (default 8; 0 disables waiting).")
|
|
394
394
|
.option("--manual-login", "Use a dedicated Chrome profile for manual login (recommended when cookie sync is unavailable).", false)
|
|
395
395
|
.option("--manual-login-profile-dir <path>", "Chrome profile directory for manual login (default ~/.oracle/browser-profile).")
|
|
396
|
+
.option("--browser-cookie-sync", "Copy cookies from this host's live Chrome profile instead of using the dedicated profile.", false)
|
|
396
397
|
.action(async (commandOptions) => {
|
|
397
398
|
const { serveRemote } = await import("../src/remote/server.js");
|
|
399
|
+
const { buildServeBrowserConfig } = await import("../src/cli/serveBrowserConfig.js");
|
|
400
|
+
const { config } = await loadUserConfig();
|
|
398
401
|
await serveRemote({
|
|
402
|
+
browserConfig: buildServeBrowserConfig(program.opts(), config),
|
|
399
403
|
host: commandOptions.host,
|
|
400
404
|
port: commandOptions.port,
|
|
401
405
|
token: commandOptions.token,
|
|
406
|
+
maxConcurrentRuns: commandOptions.maxConcurrentRuns === undefined
|
|
407
|
+
? undefined
|
|
408
|
+
: Number(commandOptions.maxConcurrentRuns),
|
|
409
|
+
maxQueuedRuns: commandOptions.maxQueuedRuns === undefined
|
|
410
|
+
? undefined
|
|
411
|
+
: Number(commandOptions.maxQueuedRuns),
|
|
402
412
|
manualLoginDefault: commandOptions.manualLogin,
|
|
403
413
|
manualLoginProfileDir: commandOptions.manualLoginProfileDir,
|
|
414
|
+
cookieSyncDefault: commandOptions.browserCookieSync,
|
|
404
415
|
});
|
|
405
416
|
});
|
|
406
417
|
const projectSourcesCommand = program
|
|
@@ -422,6 +433,7 @@ function addProjectSourcesCommonOptions(command) {
|
|
|
422
433
|
.option("--browser-cookie-path <path>", "Explicit Chrome cookie DB path.")
|
|
423
434
|
.option("--browser-inline-cookies <json>", "Inline ChatGPT cookies JSON.")
|
|
424
435
|
.option("--browser-inline-cookies-file <path>", "File containing ChatGPT cookies JSON.")
|
|
436
|
+
.option("--browser-cookie-sync", "Copy cookies from live Chrome (opt-in; token rotation may invalidate that session).")
|
|
425
437
|
.option("--browser-no-cookie-sync", "Skip copying cookies from Chrome.")
|
|
426
438
|
.option("--browser-keep-browser", "Keep Chrome running after completion.", false)
|
|
427
439
|
.option("--browser-hide-window", "Hide Chrome window after launch on macOS.", false)
|
|
@@ -709,6 +721,7 @@ function buildRunOptions(options, overrides = {}) {
|
|
|
709
721
|
background: overrides.background ?? undefined,
|
|
710
722
|
renderPlain: overrides.renderPlain ?? options.renderPlain ?? false,
|
|
711
723
|
writeOutputPath: overrides.writeOutputPath ?? options.writeOutputPath,
|
|
724
|
+
writeArtifacts: overrides.writeArtifacts ?? options.writeArtifacts ?? false,
|
|
712
725
|
};
|
|
713
726
|
}
|
|
714
727
|
function resolveApiProviderMode(options) {
|
|
@@ -948,6 +961,7 @@ function buildRunOptionsFromMetadata(metadata) {
|
|
|
948
961
|
background: stored.background,
|
|
949
962
|
renderPlain: stored.renderPlain,
|
|
950
963
|
writeOutputPath: stored.writeOutputPath,
|
|
964
|
+
writeArtifacts: stored.writeArtifacts,
|
|
951
965
|
};
|
|
952
966
|
}
|
|
953
967
|
function getSessionMode(metadata) {
|
|
@@ -1076,8 +1090,10 @@ async function runRootCommand(options) {
|
|
|
1076
1090
|
return;
|
|
1077
1091
|
}
|
|
1078
1092
|
const retentionHours = typeof options.retainHours === "number" ? options.retainHours : undefined;
|
|
1079
|
-
|
|
1080
|
-
|
|
1093
|
+
if (!previewMode) {
|
|
1094
|
+
await sessionStore.ensureStorage();
|
|
1095
|
+
await pruneOldSessions(retentionHours, (message) => console.log(chalk.dim(message)));
|
|
1096
|
+
}
|
|
1081
1097
|
if (providerMode === "openai") {
|
|
1082
1098
|
if (hasExplicitAzureOption(optionUsesDefault)) {
|
|
1083
1099
|
throw new Error("--provider openai/--no-azure cannot be combined with Azure options.");
|
|
@@ -1312,6 +1328,12 @@ async function runRootCommand(options) {
|
|
|
1312
1328
|
}
|
|
1313
1329
|
}
|
|
1314
1330
|
const activeModel = resolvedOptions.model;
|
|
1331
|
+
if (options.writeArtifacts && engine !== "browser") {
|
|
1332
|
+
throw new Error("--write-artifacts requires --engine browser.");
|
|
1333
|
+
}
|
|
1334
|
+
if (options.writeArtifacts && !resolvedOptions.writeOutputPath) {
|
|
1335
|
+
throw new Error("--write-artifacts requires --write-output <path>.");
|
|
1336
|
+
}
|
|
1315
1337
|
if (options.reasoningMode && engine !== "api") {
|
|
1316
1338
|
throw new Error("--reasoning-mode requires --engine api.");
|
|
1317
1339
|
}
|
|
@@ -1334,6 +1356,7 @@ async function runRootCommand(options) {
|
|
|
1334
1356
|
...options,
|
|
1335
1357
|
remoteHost: remoteHost ?? undefined,
|
|
1336
1358
|
model: activeModel,
|
|
1359
|
+
browserRequestedModel: cliModelArg,
|
|
1337
1360
|
browserModelLabel: resolveBrowserModelLabel(cliModelArg, activeModel),
|
|
1338
1361
|
});
|
|
1339
1362
|
return resolvedOptions.browserResumeConversationUrl
|
|
@@ -1442,6 +1465,7 @@ async function runRootCommand(options) {
|
|
|
1442
1465
|
outputPath: options.output,
|
|
1443
1466
|
aspectRatio: options.aspect,
|
|
1444
1467
|
showThoughts: options.geminiShowThoughts,
|
|
1468
|
+
allowModelFallback: options.geminiFallback,
|
|
1445
1469
|
}),
|
|
1446
1470
|
};
|
|
1447
1471
|
console.log(chalk.dim("Using Gemini web client for browser automation"));
|
|
@@ -1511,6 +1535,7 @@ async function runRootCommand(options) {
|
|
|
1511
1535
|
outputPath: options.output,
|
|
1512
1536
|
aspectRatio: options.aspect,
|
|
1513
1537
|
geminiShowThoughts: options.geminiShowThoughts,
|
|
1538
|
+
geminiAllowModelFallback: options.geminiFallback,
|
|
1514
1539
|
}, process.cwd(), notifications);
|
|
1515
1540
|
const liveRunOptions = {
|
|
1516
1541
|
...baseRunOptions,
|
|
@@ -1534,14 +1559,19 @@ async function runRootCommand(options) {
|
|
|
1534
1559
|
});
|
|
1535
1560
|
const workerPid = !detachAllowed
|
|
1536
1561
|
? undefined
|
|
1537
|
-
: await launchDetachedSession(
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1562
|
+
: await launchDetachedSession({
|
|
1563
|
+
sessionId: sessionMeta.id,
|
|
1564
|
+
cliEntrypoint: CLI_ENTRYPOINT,
|
|
1565
|
+
env: buildDetachedPerfTraceEnv(process.env, perfTraceArgs.value, sessionMeta.id),
|
|
1566
|
+
prepare: async (pid) => {
|
|
1567
|
+
lifecycle = buildSessionLifecycle({
|
|
1568
|
+
engine,
|
|
1569
|
+
detached: true,
|
|
1570
|
+
workerPid: pid,
|
|
1571
|
+
reattachCommand: `oracle session ${sessionMeta.id}`,
|
|
1572
|
+
});
|
|
1573
|
+
await sessionStore.updateSession(sessionMeta.id, { lifecycle });
|
|
1574
|
+
},
|
|
1545
1575
|
}).catch((error) => {
|
|
1546
1576
|
const message = error instanceof Error ? error.message : String(error);
|
|
1547
1577
|
console.log(chalk.yellow(`Unable to detach session runner (${message}). Running inline...`));
|
|
@@ -1629,42 +1659,6 @@ async function runInteractiveSession(sessionMeta, runOptions, mode, browserConfi
|
|
|
1629
1659
|
stream.end();
|
|
1630
1660
|
}
|
|
1631
1661
|
}
|
|
1632
|
-
async function launchDetachedSession(sessionId, prepare) {
|
|
1633
|
-
return new Promise((resolve, reject) => {
|
|
1634
|
-
try {
|
|
1635
|
-
const args = ["--", CLI_ENTRYPOINT, "--exec-session", sessionId];
|
|
1636
|
-
const env = {
|
|
1637
|
-
...buildDetachedPerfTraceEnv(process.env, perfTraceArgs.value, sessionId),
|
|
1638
|
-
ORACLE_DETACHED_START_GATE: "1",
|
|
1639
|
-
};
|
|
1640
|
-
const child = spawn(process.execPath, args, {
|
|
1641
|
-
detached: true,
|
|
1642
|
-
stdio: ["pipe", "ignore", "ignore"],
|
|
1643
|
-
env,
|
|
1644
|
-
});
|
|
1645
|
-
child.once("error", reject);
|
|
1646
|
-
child.once("spawn", async () => {
|
|
1647
|
-
if (child.pid === undefined) {
|
|
1648
|
-
reject(new Error("Detached session worker started without a process ID."));
|
|
1649
|
-
return;
|
|
1650
|
-
}
|
|
1651
|
-
try {
|
|
1652
|
-
await prepare(child.pid);
|
|
1653
|
-
child.stdin.end("ready\n");
|
|
1654
|
-
child.unref();
|
|
1655
|
-
resolve(child.pid);
|
|
1656
|
-
}
|
|
1657
|
-
catch (error) {
|
|
1658
|
-
child.kill();
|
|
1659
|
-
reject(error);
|
|
1660
|
-
}
|
|
1661
|
-
});
|
|
1662
|
-
}
|
|
1663
|
-
catch (error) {
|
|
1664
|
-
reject(error);
|
|
1665
|
-
}
|
|
1666
|
-
});
|
|
1667
|
-
}
|
|
1668
1662
|
async function waitForDetachedStartGate() {
|
|
1669
1663
|
if (process.env.ORACLE_DETACHED_START_GATE !== "1") {
|
|
1670
1664
|
return;
|
|
@@ -1789,6 +1783,7 @@ async function restartSession(sessionId, options) {
|
|
|
1789
1783
|
outputPath: storedOptions.outputPath,
|
|
1790
1784
|
aspectRatio: storedOptions.aspectRatio,
|
|
1791
1785
|
showThoughts: storedOptions.geminiShowThoughts,
|
|
1786
|
+
allowModelFallback: storedOptions.geminiAllowModelFallback,
|
|
1792
1787
|
}),
|
|
1793
1788
|
};
|
|
1794
1789
|
console.log(chalk.dim("Using Gemini web client for browser automation"));
|
|
@@ -1815,6 +1810,7 @@ async function restartSession(sessionId, options) {
|
|
|
1815
1810
|
outputPath: storedOptions.outputPath,
|
|
1816
1811
|
aspectRatio: storedOptions.aspectRatio,
|
|
1817
1812
|
geminiShowThoughts: storedOptions.geminiShowThoughts,
|
|
1813
|
+
geminiAllowModelFallback: storedOptions.geminiAllowModelFallback,
|
|
1818
1814
|
}, cwd, notifications, sessionId);
|
|
1819
1815
|
const liveRunOptions = {
|
|
1820
1816
|
...runOptions,
|
|
@@ -1838,14 +1834,19 @@ async function restartSession(sessionId, options) {
|
|
|
1838
1834
|
});
|
|
1839
1835
|
const workerPid = !detachAllowed
|
|
1840
1836
|
? undefined
|
|
1841
|
-
: await launchDetachedSession(
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1837
|
+
: await launchDetachedSession({
|
|
1838
|
+
sessionId: sessionMeta.id,
|
|
1839
|
+
cliEntrypoint: CLI_ENTRYPOINT,
|
|
1840
|
+
env: buildDetachedPerfTraceEnv(process.env, perfTraceArgs.value, sessionMeta.id),
|
|
1841
|
+
prepare: async (pid) => {
|
|
1842
|
+
lifecycle = buildSessionLifecycle({
|
|
1843
|
+
engine,
|
|
1844
|
+
detached: true,
|
|
1845
|
+
workerPid: pid,
|
|
1846
|
+
reattachCommand: `oracle session ${sessionMeta.id}`,
|
|
1847
|
+
});
|
|
1848
|
+
await sessionStore.updateSession(sessionMeta.id, { lifecycle });
|
|
1849
|
+
},
|
|
1849
1850
|
}).catch((error) => {
|
|
1850
1851
|
const message = error instanceof Error ? error.message : String(error);
|
|
1851
1852
|
console.log(chalk.yellow(`Unable to detach session runner (${message}). Running inline...`));
|
|
@@ -1981,6 +1982,10 @@ function printDebugHelp(cliName) {
|
|
|
1981
1982
|
"--browser-cookie-wait <ms|s|m>",
|
|
1982
1983
|
"Wait before retrying cookie sync when Chrome cookies are empty or locked.",
|
|
1983
1984
|
],
|
|
1985
|
+
[
|
|
1986
|
+
"--browser-cookie-sync",
|
|
1987
|
+
"Copy cookies from live Chrome (opt-in; token rotation may invalidate that session).",
|
|
1988
|
+
],
|
|
1984
1989
|
["--browser-no-cookie-sync", "Skip copying cookies from your main profile."],
|
|
1985
1990
|
[
|
|
1986
1991
|
"--browser-manual-login",
|
|
@@ -2029,6 +2034,12 @@ program.action(async function () {
|
|
|
2029
2034
|
await runRootCommand(options);
|
|
2030
2035
|
});
|
|
2031
2036
|
async function main() {
|
|
2037
|
+
// npx runs the default binary; let the MCP transport own the alias lifetime.
|
|
2038
|
+
if (process.argv[2] === "oracle-mcp") {
|
|
2039
|
+
const { startMcpServer } = await import("../src/mcp/server.js");
|
|
2040
|
+
await startMcpServer();
|
|
2041
|
+
return;
|
|
2042
|
+
}
|
|
2032
2043
|
if (perfTraceArgs.error) {
|
|
2033
2044
|
console.error(`error: ${perfTraceArgs.error}`);
|
|
2034
2045
|
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' ||
|