@steipete/oracle 0.11.0 → 0.11.1

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
@@ -243,7 +243,7 @@ Browser automation can open or control Chrome, so dry-runs and live runs print a
243
243
  | `--followup <sessionId\|responseId>` | Continue an OpenAI/Azure Responses API run from a stored oracle session or `resp_...` response id. |
244
244
  | `--followup-model <model>` | For multi-model OpenAI/Azure parent sessions, choose which model response to continue from. |
245
245
  | `--base-url <url>` | Point API runs at LiteLLM/Azure/OpenRouter/etc. |
246
- | `--chatgpt-url <url>` | Target a ChatGPT workspace/folder (browser). |
246
+ | `--chatgpt-url <url>` | Target a ChatGPT workspace/folder or Temporary Chat URL (browser). |
247
247
  | `--browser-model-strategy <select\|current\|ignore>` | Control ChatGPT model selection in browser mode (current keeps the active model; ignore skips the picker). |
248
248
  | `--browser-manual-login` | Skip cookie copy; reuse a persistent automation profile and wait for manual ChatGPT login. |
249
249
  | `--browser-attach-running` | Reuse your current local browser session through local `DevToolsActivePort` discovery; Oracle opens a dedicated tab instead of launching Chrome (defaults to `127.0.0.1:9222`, or combine with `--remote-chrome <host:port>` to hint a different local endpoint). |
@@ -1,6 +1,15 @@
1
1
  export function isProjectChatgptUrl(url) {
2
2
  return /\/project(?:[/?#]|$)/i.test(url ?? "");
3
3
  }
4
+ export function isTemporaryChatgptUrl(url) {
5
+ try {
6
+ const parsed = new URL(url ?? "");
7
+ return (parsed.searchParams.get("temporary-chat") ?? "").trim().toLowerCase() === "true";
8
+ }
9
+ catch {
10
+ return false;
11
+ }
12
+ }
4
13
  export function resolveBrowserArchiveDecision({ mode = "auto", chatgptUrl, conversationUrl, researchMode, followUpCount, }) {
5
14
  if (mode === "never") {
6
15
  return { mode, shouldArchive: false, reason: "disabled" };
@@ -8,6 +17,9 @@ export function resolveBrowserArchiveDecision({ mode = "auto", chatgptUrl, conve
8
17
  if (!conversationUrl) {
9
18
  return { mode, shouldArchive: false, reason: "missing-conversation-url" };
10
19
  }
20
+ if (isTemporaryChatgptUrl(chatgptUrl) || isTemporaryChatgptUrl(conversationUrl)) {
21
+ return { mode, shouldArchive: false, reason: "temporary-chat" };
22
+ }
11
23
  if (mode === "always") {
12
24
  return { mode, shouldArchive: true, reason: "forced" };
13
25
  }
@@ -25,7 +25,7 @@ export async function ensureModelSelection(Runtime, desiredModel, logger, strate
25
25
  const available = (result.hint?.availableOptions ?? []).filter(Boolean);
26
26
  const availableHint = available.length > 0 ? ` Available: ${available.join(", ")}.` : "";
27
27
  const tempHint = isTemporary && /\bpro\b/i.test(desiredModel)
28
- ? ' You are in Temporary Chat mode; Pro models are not available there. Remove "temporary-chat=true" from --chatgpt-url or use a non-Pro model (e.g. gpt-5.2).'
28
+ ? " You are in Temporary Chat mode; model labels may differ there. If the current Temporary Chat already shows the desired Pro mode, retry with --browser-model-strategy current; otherwise choose an available model or turn Temporary Chat off."
29
29
  : "";
30
30
  throw new Error(`Unable to find model option matching "${desiredModel}" in the model switcher.${availableHint}${tempHint}`);
31
31
  }
@@ -52,7 +52,7 @@ function assertResolvedModelSelection(desiredModel, resolvedLabel) {
52
52
  resolved.includes("gpt-5.5-pro") ||
53
53
  resolved.includes("gpt 5 5 pro");
54
54
  if (!hasProSignal || (resolved.includes("thinking") && !resolved.includes("pro"))) {
55
- throw new Error(`Model picker selected "${resolvedLabel}" while "${desiredModel}" requires GPT-5.5 Pro Extended. Use model "gpt-5.5" with browser thinking time "heavy" for Thinking Heavy.`);
55
+ throw new Error(`Model picker selected "${resolvedLabel}" while "${desiredModel}" requires GPT-5.5 Pro. Use model "gpt-5.5" with browser thinking time for the Thinking variant.`);
56
56
  }
57
57
  }
58
58
  export function assertResolvedModelSelectionForTest(desiredModel, resolvedLabel) {
@@ -125,10 +125,15 @@ function buildModelSelectionExpression(targetModel, strategy) {
125
125
  if (desiredVersion !== '5-5') return false;
126
126
  const label = normalizeText(value);
127
127
  if (wantsPro) {
128
- return label.includes('pro') && label.includes('extended') && !label.includes('thinking');
128
+ // ChatGPT UI as of 2026-05: the picker shows just "Pro" (no longer "Pro Extended").
129
+ // "Extended" is now a thinking-effort sub-setting, not part of the model label.
130
+ // Accept bare "pro", legacy "pro extended", and reversed "extended pro" (composer pill).
131
+ return (label === 'pro' || label === 'pro extended' || label === 'extended pro') && !label.includes('thinking');
129
132
  }
130
133
  if (wantsThinking) {
131
- return label.includes('thinking') && label.includes('heavy') && !label.includes('pro');
134
+ // ChatGPT UI as of 2026-05: the picker shows "Thinking" or "Thinking · Extended"
135
+ // (normalized to "thinking extended"). Accept both old "thinking heavy" and new labels.
136
+ return (label === 'thinking' || label === 'thinking extended' || label === 'thinking heavy') && !label.includes('pro');
132
137
  }
133
138
  return false;
134
139
  };
@@ -1,7 +1,7 @@
1
1
  import { CHATGPT_URL, DEEP_RESEARCH_DEFAULT_TIMEOUT_MS, DEFAULT_MODEL_STRATEGY, DEFAULT_MODEL_TARGET, } from "./constants.js";
2
2
  import { normalizeBrowserModelStrategy } from "./modelStrategy.js";
3
3
  import { DEFAULT_MAX_CONCURRENT_CHATGPT_TABS, normalizeMaxConcurrentTabs, } from "./tabLeaseRegistry.js";
4
- import { isTemporaryChatUrl, normalizeChatgptUrl } from "./utils.js";
4
+ import { normalizeChatgptUrl } from "./utils.js";
5
5
  import os from "node:os";
6
6
  import path from "node:path";
7
7
  export const DEFAULT_CHATGPT_COOKIE_NAMES = [
@@ -65,12 +65,6 @@ export function resolveBrowserConfig(config) {
65
65
  const modelStrategy = normalizeBrowserModelStrategy(config?.modelStrategy) ??
66
66
  DEFAULT_BROWSER_CONFIG.modelStrategy ??
67
67
  DEFAULT_MODEL_STRATEGY;
68
- if (modelStrategy === "select" &&
69
- isTemporaryChatUrl(normalizedUrl) &&
70
- /\bpro\b/i.test(desiredModel)) {
71
- throw new Error("Temporary Chat mode does not expose Pro models in the ChatGPT model picker. " +
72
- 'Remove "temporary-chat=true" from your browser URL, or use a non-Pro model label (e.g. "GPT-5.2").');
73
- }
74
68
  const isWindows = process.platform === "win32";
75
69
  const manualLogin = config?.manualLogin ?? (isWindows ? true : DEFAULT_BROWSER_CONFIG.manualLogin);
76
70
  const cookieSyncDefault = isWindows ? false : DEFAULT_BROWSER_CONFIG.cookieSync;
@@ -70,19 +70,12 @@ export function shouldPreserveBrowserOnErrorForTest(error, headless) {
70
70
  export function classifyPreservedBrowserErrorForTest(error, headless) {
71
71
  return classifyPreservedBrowserError(error, headless);
72
72
  }
73
- function shouldSkipThinkingTimeSelection(desiredModel, thinkingTime) {
74
- if (thinkingTime !== "extended" || !desiredModel) {
75
- return false;
76
- }
77
- const normalized = desiredModel.toLowerCase();
78
- return (normalized === "gpt-5.5-pro" ||
79
- normalized.includes("gpt-5.5 pro") ||
80
- normalized.includes("gpt 5.5 pro") ||
81
- normalized.includes("gpt 5 5 pro"));
82
- }
83
- export function shouldSkipThinkingTimeSelectionForTest(desiredModel, thinkingTime) {
84
- return shouldSkipThinkingTimeSelection(desiredModel, thinkingTime);
85
- }
73
+ // NOTE: Previously, shouldSkipThinkingTimeSelection() would skip the thinking
74
+ // time UI step when desiredModel was gpt-5.5-pro and thinkingTime was "extended",
75
+ // assuming that selecting "Pro Extended" in the old UI already implied Extended
76
+ // effort. This is wrong for lower-tier plans ($100/mo Pro) where selecting "Pro"
77
+ // defaults to Standard effort. ensureThinkingTime() already handles the
78
+ // "already-selected" case as a no-op, so always attempting it is safe.
86
79
  function listIgnoredRemoteChromeFlags(config) {
87
80
  return [
88
81
  config.headless ? "--browser-headless" : null,
@@ -712,20 +705,15 @@ export async function runBrowserMode(options) {
712
705
  // Handle thinking time selection if specified. Deep Research owns its own effort flow.
713
706
  const thinkingTime = config.thinkingTime;
714
707
  if (thinkingTime && !deepResearch) {
715
- if (shouldSkipThinkingTimeSelection(config.desiredModel, thinkingTime)) {
716
- logger("Thinking time: Pro Extended (via model selection)");
717
- }
718
- else {
719
- await raceWithDisconnect(withRetries(() => ensureThinkingTime(Runtime, thinkingTime, logger), {
720
- retries: 2,
721
- delayMs: 300,
722
- onRetry: (attempt, error) => {
723
- if (options.verbose) {
724
- logger(`[retry] Thinking time (${thinkingTime}) attempt ${attempt + 1}: ${error instanceof Error ? error.message : error}`);
725
- }
726
- },
727
- }));
728
- }
708
+ await raceWithDisconnect(withRetries(() => ensureThinkingTime(Runtime, thinkingTime, logger), {
709
+ retries: 2,
710
+ delayMs: 300,
711
+ onRetry: (attempt, error) => {
712
+ if (options.verbose) {
713
+ logger(`[retry] Thinking time (${thinkingTime}) attempt ${attempt + 1}: ${error instanceof Error ? error.message : error}`);
714
+ }
715
+ },
716
+ }));
729
717
  }
730
718
  if (deepResearch) {
731
719
  await raceWithDisconnect(withRetries(() => activateDeepResearch(Runtime, Input, logger), {
@@ -1832,20 +1820,15 @@ async function runRemoteBrowserMode(promptText, attachments, config, logger, opt
1832
1820
  // Handle thinking time selection if specified. Deep Research owns its own effort flow.
1833
1821
  const thinkingTime = config.thinkingTime;
1834
1822
  if (thinkingTime && !deepResearch) {
1835
- if (shouldSkipThinkingTimeSelection(config.desiredModel, thinkingTime)) {
1836
- logger("Thinking time: Pro Extended (via model selection)");
1837
- }
1838
- else {
1839
- await withRetries(() => ensureThinkingTime(Runtime, thinkingTime, logger), {
1840
- retries: 2,
1841
- delayMs: 300,
1842
- onRetry: (attempt, error) => {
1843
- if (options.verbose) {
1844
- logger(`[retry] Thinking time (${thinkingTime}) attempt ${attempt + 1}: ${error instanceof Error ? error.message : error}`);
1845
- }
1846
- },
1847
- });
1848
- }
1823
+ await withRetries(() => ensureThinkingTime(Runtime, thinkingTime, logger), {
1824
+ retries: 2,
1825
+ delayMs: 300,
1826
+ onRetry: (attempt, error) => {
1827
+ if (options.verbose) {
1828
+ logger(`[retry] Thinking time (${thinkingTime}) attempt ${attempt + 1}: ${error instanceof Error ? error.message : error}`);
1829
+ }
1830
+ },
1831
+ });
1849
1832
  }
1850
1833
  if (deepResearch) {
1851
1834
  await withRetries(() => activateDeepResearch(Runtime, Input, logger), {
@@ -1,6 +1,6 @@
1
1
  import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
- import { CHATGPT_URL, DEFAULT_MODEL_STRATEGY, DEFAULT_MODEL_TARGET, isTemporaryChatUrl, normalizeChatgptUrl, parseDuration, } from "../browserMode.js";
3
+ import { CHATGPT_URL, DEFAULT_MODEL_STRATEGY, DEFAULT_MODEL_TARGET, normalizeChatgptUrl, parseDuration, } from "../browserMode.js";
4
4
  import { normalizeBrowserModelStrategy } from "../browser/modelStrategy.js";
5
5
  import { getOracleHomeDir } from "../oracleHome.js";
6
6
  const DEFAULT_BROWSER_TIMEOUT_MS = 1_200_000;
@@ -86,13 +86,6 @@ export async function buildBrowserConfig(options) {
86
86
  : shouldUseOverride
87
87
  ? desiredModelOverride
88
88
  : mapModelToBrowserLabel(options.model);
89
- if (modelStrategy === "select" &&
90
- url &&
91
- isTemporaryChatUrl(url) &&
92
- /\bpro\b/i.test(desiredModel ?? "")) {
93
- throw new Error("Temporary Chat mode does not expose Pro models in the ChatGPT model picker. " +
94
- 'Remove "temporary-chat=true" from --chatgpt-url (or omit --chatgpt-url), or use a non-Pro model (e.g. --model gpt-5.2).');
95
- }
96
89
  return {
97
90
  chromeProfile: options.browserChromeProfile ?? DEFAULT_CHROME_PROFILE,
98
91
  chromePath: options.browserChromePath ?? null,
@@ -1,6 +1,7 @@
1
1
  import { z } from "zod";
2
2
  export const CONSULT_PRESETS = ["chatgpt-pro-heavy"];
3
- export const consultInputSchema = z.object({
3
+ export const consultInputSchema = z
4
+ .object({
4
5
  preset: z.enum(CONSULT_PRESETS).optional(),
5
6
  prompt: z.string().min(1, "Prompt is required."),
6
7
  files: z.array(z.string()).default([]),
@@ -19,7 +20,8 @@ export const consultInputSchema = z.object({
19
20
  dryRun: z.boolean().optional(),
20
21
  search: z.boolean().optional(),
21
22
  slug: z.string().optional(),
22
- });
23
+ })
24
+ .strict();
23
25
  export const sessionsInputSchema = z.object({
24
26
  id: z.string().optional(),
25
27
  hours: z.number().optional(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@steipete/oracle",
3
- "version": "0.11.0",
3
+ "version": "0.11.1",
4
4
  "description": "CLI wrapper around OpenAI Responses API with GPT-5.5 Pro, GPT-5.5, GPT-5.4, GPT-5.2, GPT-5.1, and GPT-5.1 Codex high reasoning modes.",
5
5
  "keywords": [],
6
6
  "homepage": "https://github.com/steipete/oracle#readme",
@@ -56,7 +56,7 @@
56
56
  },
57
57
  "dependencies": {
58
58
  "@anthropic-ai/tokenizer": "^0.0.4",
59
- "@google/genai": "^1.51.0",
59
+ "@google/genai": "^2.0.1",
60
60
  "@google/generative-ai": "^0.24.1",
61
61
  "@modelcontextprotocol/sdk": "^1.29.0",
62
62
  "@steipete/sweet-cookie": "^0.2.0",
@@ -85,12 +85,12 @@
85
85
  "@types/chrome-remote-interface": "^0.33.0",
86
86
  "@types/inquirer": "^9.0.9",
87
87
  "@types/node": "^25.6.0",
88
- "@typescript/native-preview": "7.0.0-dev.20260503.1",
88
+ "@typescript/native-preview": "7.0.0-dev.20260508.1",
89
89
  "@vitest/coverage-v8": "4.1.5",
90
- "devtools-protocol": "0.0.1624250",
90
+ "devtools-protocol": "0.0.1627472",
91
91
  "es-toolkit": "^1.46.1",
92
92
  "esbuild": "^0.28.0",
93
- "oxfmt": "0.47.0",
93
+ "oxfmt": "0.48.0",
94
94
  "oxlint": "^1.62.0",
95
95
  "puppeteer-core": "^24.42.0",
96
96
  "tsx": "^4.21.0",
@@ -111,7 +111,7 @@
111
111
  "packageManager": "pnpm@10.33.2",
112
112
  "pnpm": {
113
113
  "overrides": {
114
- "devtools-protocol": "0.0.1624250"
114
+ "devtools-protocol": "0.0.1627472"
115
115
  },
116
116
  "onlyBuiltDependencies": [
117
117
  "esbuild"