@steipete/oracle 0.7.5 → 0.8.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 CHANGED
@@ -11,13 +11,14 @@
11
11
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green?style=for-the-badge" alt="MIT License"></a>
12
12
  </p>
13
13
 
14
- Oracle bundles your prompt and files so another AI can answer with real context. It speaks GPT-5.1 Pro (default alias to GPT-5.2 Pro on the API), GPT-5.1 Codex (API-only), GPT-5.1, GPT-5.2, Gemini 3 Pro, Claude Sonnet 4.5, Claude Opus 4.1, and more—and it can ask one or multiple models in a single run. Browser automation is available; API remains the most reliable path, and `--copy` is an easy manual fallback.
14
+ Oracle bundles your prompt and files so another AI can answer with real context. It speaks GPT-5.1 Pro (default alias to GPT-5.2 Pro on the API), GPT-5.1 Codex (API-only), GPT-5.1, GPT-5.2, Gemini 3 Pro, Claude Sonnet 4.5, Claude Opus 4.1, and more—and it can ask one or multiple models in a single run. Browser automation is available; use `--browser-model-strategy current` to keep the active ChatGPT model (or `ignore` to skip the picker). API remains the most reliable path, and `--copy` is an easy manual fallback.
15
15
 
16
16
  ## Quick start
17
17
 
18
18
  Install globally: `npm install -g @steipete/oracle`
19
+ Homebrew: `brew install steipete/tap/oracle`
19
20
 
20
- Use `npx -y @steipete/oracle …` (not `pnpx`)—pnpx's sandboxed cache can’t load the sqlite bindings and will throw missing `node_sqlite3.node` errors.
21
+ Requires Node 22+. Prefer `npx -y @steipete/oracle …` (pnpx can be quirky with ESM caching).
21
22
 
22
23
  ```bash
23
24
  # Copy the bundle and paste into ChatGPT
@@ -110,6 +111,7 @@ npx -y @steipete/oracle oracle-mcp
110
111
  | `--models <list>` | Comma-separated API models (mix built-ins and OpenRouter ids) for multi-model runs. |
111
112
  | `--base-url <url>` | Point API runs at LiteLLM/Azure/OpenRouter/etc. |
112
113
  | `--chatgpt-url <url>` | Target a ChatGPT workspace/folder (browser). |
114
+ | `--browser-model-strategy <select\|current\|ignore>` | Control ChatGPT model selection in browser mode (current keeps the active model; ignore skips the picker). |
113
115
  | `--browser-port <port>` | Pin the Chrome DevTools port (WSL/Windows firewall helper). |
114
116
  | `--browser-inline-cookies[(-file)] <payload|path>` | Supply cookies without Chrome/Keychain (browser). |
115
117
  | `--browser-timeout`, `--browser-input-timeout` | Control overall/browser input timeouts (supports h/m/s/ms). |
@@ -20,7 +20,7 @@ import { CHATGPT_URL } from '../src/browserMode.js';
20
20
  import { createRemoteBrowserExecutor } from '../src/remote/client.js';
21
21
  import { createGeminiWebExecutor } from '../src/gemini-web/index.js';
22
22
  import { applyHelpStyling } from '../src/cli/help.js';
23
- import { collectPaths, collectModelList, parseFloatOption, parseIntOption, parseSearchOption, usesDefaultStatusFilters, resolvePreviewMode, normalizeModelOption, normalizeBaseUrl, resolveApiModel, inferModelFromLabel, parseHeartbeatOption, parseTimeoutOption, mergePathLikeOptions, } from '../src/cli/options.js';
23
+ import { collectPaths, collectModelList, parseFloatOption, parseIntOption, parseSearchOption, usesDefaultStatusFilters, resolvePreviewMode, normalizeModelOption, normalizeBaseUrl, resolveApiModel, inferModelFromLabel, parseHeartbeatOption, parseTimeoutOption, mergePathLikeOptions, dedupePathInputs, } from '../src/cli/options.js';
24
24
  import { copyToClipboard } from '../src/cli/clipboard.js';
25
25
  import { buildMarkdownBundle } from '../src/cli/markdownBundle.js';
26
26
  import { shouldDetachSession } from '../src/cli/detach.js';
@@ -174,6 +174,7 @@ program
174
174
  .addOption(new Option('--browser-headless', 'Launch Chrome in headless mode.').hideHelp())
175
175
  .addOption(new Option('--browser-hide-window', 'Hide the Chrome window after launch (macOS headful only).').hideHelp())
176
176
  .addOption(new Option('--browser-keep-browser', 'Keep Chrome running after completion.').hideHelp())
177
+ .addOption(new Option('--browser-model-strategy <mode>', 'ChatGPT model picker strategy: select (default) switches to the requested model, current keeps the active model, ignore skips the picker entirely.').choices(['select', 'current', 'ignore']))
177
178
  .addOption(new Option('--browser-thinking-time <level>', 'Thinking time intensity for Thinking/Pro models: light, standard, extended, heavy.')
178
179
  .choices(['light', 'standard', 'extended', 'heavy'])
179
180
  .hideHelp())
@@ -420,7 +421,13 @@ async function runRootCommand(options) {
420
421
  const previewMode = resolvePreviewMode(options.dryRun || options.preview);
421
422
  const mergedFileInputs = mergePathLikeOptions(options.file, options.include, options.files, options.path, options.paths);
422
423
  if (mergedFileInputs.length > 0) {
423
- options.file = mergedFileInputs;
424
+ const { deduped, duplicates } = dedupePathInputs(mergedFileInputs, { cwd: process.cwd() });
425
+ if (duplicates.length > 0) {
426
+ const preview = duplicates.slice(0, 8).join(', ');
427
+ const suffix = duplicates.length > 8 ? ` (+${duplicates.length - 8} more)` : '';
428
+ console.log(chalk.dim(`Ignoring duplicate --file inputs: ${preview}${suffix}`));
429
+ }
430
+ options.file = deduped;
424
431
  }
425
432
  const copyMarkdown = options.copyMarkdown || options.copy;
426
433
  const renderMarkdown = resolveRenderFlag(options.render, options.renderMarkdown);
@@ -719,6 +726,9 @@ async function runRootCommand(options) {
719
726
  }),
720
727
  };
721
728
  console.log(chalk.dim('Using Gemini web client for browser automation'));
729
+ if (browserConfig.modelStrategy && browserConfig.modelStrategy !== 'select') {
730
+ console.log(chalk.dim('Browser model strategy is ignored for Gemini web runs.'));
731
+ }
722
732
  }
723
733
  const remoteExecutionActive = Boolean(browserDeps);
724
734
  if (options.dryRun) {