@andrewting19/oracle 0.10.3 → 0.11.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/dist/bin/oracle-cli.js
CHANGED
|
@@ -470,8 +470,11 @@ function resolveHeartbeatIntervalMs(seconds) {
|
|
|
470
470
|
return Math.round(seconds * 1000);
|
|
471
471
|
}
|
|
472
472
|
function assertFollowupSupported({ engine, model, baseUrl, azureEndpoint, }) {
|
|
473
|
+
// Browser engine: follow-up navigates to an existing ChatGPT conversation URL.
|
|
474
|
+
if (engine === "browser")
|
|
475
|
+
return;
|
|
473
476
|
if (engine !== "api") {
|
|
474
|
-
throw new Error("--followup requires --engine api.");
|
|
477
|
+
throw new Error("--followup requires --engine api or --engine browser.");
|
|
475
478
|
}
|
|
476
479
|
if (model.startsWith("gemini") || model.startsWith("claude")) {
|
|
477
480
|
throw new Error(`--followup is only supported for OpenAI Responses API runs. Model ${model} uses a provider client without previous_response_id support.`);
|
|
@@ -538,7 +541,7 @@ async function suggestFollowupSessionIds(input, limit = 3) {
|
|
|
538
541
|
.slice(0, limit);
|
|
539
542
|
return ranked.map((entry) => entry.id);
|
|
540
543
|
}
|
|
541
|
-
async function resolveFollowupReference(value, followupModel) {
|
|
544
|
+
async function resolveFollowupReference(value, followupModel, engine) {
|
|
542
545
|
const trimmed = value.trim();
|
|
543
546
|
if (trimmed.length === 0) {
|
|
544
547
|
throw new Error("--followup requires a session id or response id.");
|
|
@@ -555,6 +558,14 @@ async function resolveFollowupReference(value, followupModel) {
|
|
|
555
558
|
: "";
|
|
556
559
|
throw new Error(`No session found with ID ${trimmed}.${suggestionText} Run "oracle status --hours 72 --limit 20" to list recent sessions.`);
|
|
557
560
|
}
|
|
561
|
+
// Browser follow-up: extract conversation URL from the parent session.
|
|
562
|
+
if (engine === "browser") {
|
|
563
|
+
const conversationUrl = meta.browser?.runtime?.tabUrl;
|
|
564
|
+
if (!conversationUrl || !conversationUrl.includes("/c/")) {
|
|
565
|
+
throw new Error(`Session "${trimmed}" has no ChatGPT conversation URL stored. Cannot follow up in browser mode.`);
|
|
566
|
+
}
|
|
567
|
+
return { sessionId: meta.id, conversationUrl };
|
|
568
|
+
}
|
|
558
569
|
const fromMetadata = extractResponseIdFromSession(meta, followupModel);
|
|
559
570
|
if (fromMetadata) {
|
|
560
571
|
return { responseId: fromMetadata, sessionId: meta.id };
|
|
@@ -917,7 +928,7 @@ async function runRootCommand(options) {
|
|
|
917
928
|
if (normalizedMultiModels.length > 0) {
|
|
918
929
|
throw new Error("--followup cannot be combined with --models.");
|
|
919
930
|
}
|
|
920
|
-
const followup = await resolveFollowupReference(options.followup, options.followupModel);
|
|
931
|
+
const followup = await resolveFollowupReference(options.followup, options.followupModel, engine);
|
|
921
932
|
resolvedOptions.previousResponseId = followup.responseId;
|
|
922
933
|
resolvedOptions.followupSessionId = followup.sessionId;
|
|
923
934
|
resolvedOptions.followupModel = options.followupModel;
|
|
@@ -964,6 +975,7 @@ async function runRootCommand(options) {
|
|
|
964
975
|
options.prompt = `${options.prompt.trim()}\n${userConfig.promptSuffix}`;
|
|
965
976
|
}
|
|
966
977
|
resolvedOptions.prompt = options.prompt;
|
|
978
|
+
let browserFollowupConversationUrl;
|
|
967
979
|
if (options.followup) {
|
|
968
980
|
assertFollowupSupported({
|
|
969
981
|
engine,
|
|
@@ -974,10 +986,11 @@ async function runRootCommand(options) {
|
|
|
974
986
|
if (normalizedMultiModels.length > 0) {
|
|
975
987
|
throw new Error("--followup cannot be combined with --models.");
|
|
976
988
|
}
|
|
977
|
-
const followup = await resolveFollowupReference(options.followup, options.followupModel);
|
|
989
|
+
const followup = await resolveFollowupReference(options.followup, options.followupModel, engine);
|
|
978
990
|
resolvedOptions.previousResponseId = followup.responseId;
|
|
979
991
|
resolvedOptions.followupSessionId = followup.sessionId;
|
|
980
992
|
resolvedOptions.followupModel = options.followupModel;
|
|
993
|
+
browserFollowupConversationUrl = followup.conversationUrl;
|
|
981
994
|
}
|
|
982
995
|
const duplicateBlocked = await shouldBlockDuplicatePrompt({
|
|
983
996
|
prompt: resolvedOptions.prompt,
|
|
@@ -1018,6 +1031,13 @@ async function runRootCommand(options) {
|
|
|
1018
1031
|
browserModelLabel: browserModelLabelOverride,
|
|
1019
1032
|
})
|
|
1020
1033
|
: undefined;
|
|
1034
|
+
// For browser follow-ups, navigate to the existing conversation and skip model selection.
|
|
1035
|
+
if (browserConfig && browserFollowupConversationUrl) {
|
|
1036
|
+
browserConfig.url = browserFollowupConversationUrl;
|
|
1037
|
+
browserConfig.chatgptUrl = browserFollowupConversationUrl;
|
|
1038
|
+
browserConfig.modelStrategy = "ignore";
|
|
1039
|
+
console.log(chalk.dim(`Following up on conversation: ${browserFollowupConversationUrl}`));
|
|
1040
|
+
}
|
|
1021
1041
|
let browserDeps;
|
|
1022
1042
|
if (browserConfig && remoteHost) {
|
|
1023
1043
|
browserDeps = {
|
|
@@ -124,6 +124,8 @@ export async function runBrowserSessionExecution({ runOptions, browserConfig, cw
|
|
|
124
124
|
chromePort: browserResult.chromePort,
|
|
125
125
|
chromeHost: browserResult.chromeHost,
|
|
126
126
|
userDataDir: browserResult.userDataDir,
|
|
127
|
+
chromeTargetId: browserResult.chromeTargetId,
|
|
128
|
+
tabUrl: browserResult.tabUrl,
|
|
127
129
|
controllerPid: browserResult.controllerPid ?? process.pid,
|
|
128
130
|
},
|
|
129
131
|
answerText,
|
|
@@ -12,6 +12,7 @@ import { CHATGPT_URL } from "../browser/constants.js";
|
|
|
12
12
|
import { getCliVersion } from "../version.js";
|
|
13
13
|
import { cleanupStaleProfileState, readDevToolsPort, verifyDevToolsReachable, writeChromePid, writeDevToolsActivePort, } from "../browser/profileState.js";
|
|
14
14
|
import { normalizeChatgptUrl } from "../browser/utils.js";
|
|
15
|
+
import { hideChromeWindow } from "../browser/chromeLifecycle.js";
|
|
15
16
|
async function findAvailablePort() {
|
|
16
17
|
return await new Promise((resolve, reject) => {
|
|
17
18
|
const srv = net.createServer();
|
|
@@ -354,6 +355,14 @@ export async function serveRemote(options = {}) {
|
|
|
354
355
|
const msg = cookieErr instanceof Error ? cookieErr.message : String(cookieErr);
|
|
355
356
|
console.log(`Warning: failed to sync cookies into shared Chrome (${msg}). Runs may need to authenticate.`);
|
|
356
357
|
}
|
|
358
|
+
// Hide the serve Chrome from the macOS Dock (set visible = false).
|
|
359
|
+
// This is safe because we interact via CDP, not GUI.
|
|
360
|
+
try {
|
|
361
|
+
await hideChromeWindow(chrome, console.log);
|
|
362
|
+
}
|
|
363
|
+
catch {
|
|
364
|
+
// Non-fatal: hideChromeWindow logs its own errors.
|
|
365
|
+
}
|
|
357
366
|
sharedChrome = { host: "127.0.0.1", port: chrome.port, rootSession };
|
|
358
367
|
}
|
|
359
368
|
catch (error) {
|
|
@@ -414,6 +423,7 @@ function sanitizeResult(result) {
|
|
|
414
423
|
tookMs: result.tookMs,
|
|
415
424
|
answerTokens: result.answerTokens,
|
|
416
425
|
answerChars: result.answerChars,
|
|
426
|
+
tabUrl: result.tabUrl,
|
|
417
427
|
chromePid: undefined,
|
|
418
428
|
chromePort: undefined,
|
|
419
429
|
userDataDir: undefined,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@andrewting19/oracle",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "CLI wrapper around OpenAI Responses API with GPT-5.4 Pro, 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",
|