@steipete/oracle 0.20.0 → 0.20.2
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 +66 -25
- package/dist/src/browser/actions/modelSelection.js +36 -4
- package/dist/src/browser/actions/thinkingTime.js +11 -5
- package/dist/src/browser/browserConnection.js +59 -0
- package/dist/src/browser/chatgptImages.js +1 -1
- package/dist/src/browser/chromeLifecycle.js +105 -36
- package/dist/src/browser/index.js +41 -8
- package/dist/src/browser/liveTabs.js +94 -29
- package/dist/src/browser/profileState.js +6 -1
- package/dist/src/browser/promptFingerprint.js +54 -0
- package/dist/src/browser/reattach.js +157 -108
- package/dist/src/browser/recoveryTarget.js +31 -6
- package/dist/src/browser/sessionRunner.js +30 -7
- package/dist/src/browser/targetClaim.js +2 -2
- package/dist/src/cli/browserDefaults.js +3 -0
- package/dist/src/cli/browserTabs.js +105 -20
- package/dist/src/cli/detach.js +10 -1
- package/dist/src/cli/detachedSession.js +36 -0
- package/dist/src/cli/errorUtils.js +9 -0
- package/dist/src/cli/sessionDisplay.js +11 -3
- package/dist/src/cli/sessionRunner.js +150 -37
- package/dist/src/mcp/tools/consult.js +1 -7
- package/dist/src/remote/client.js +71 -14
- package/dist/src/remote/health.js +1 -0
- package/dist/src/remote/server.js +52 -10
- package/dist/src/remote/types.js +13 -0
- package/dist/src/sessionManager.js +8 -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 +9 -9
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/CodeResources +0 -0
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/MacOS/OracleNotifier +0 -0
|
@@ -14,20 +14,21 @@ import { resolveBrowserConfig } from "../browser/config.js";
|
|
|
14
14
|
import { RunSlots } from "./runSlots.js";
|
|
15
15
|
export { RunSlots } from "./runSlots.js";
|
|
16
16
|
import { loadUserConfig } from "../config.js";
|
|
17
|
-
import { MAX_REMOTE_ARTIFACT_BYTES } from "./types.js";
|
|
17
|
+
import { MAX_REMOTE_ARTIFACT_BYTES, pickRemoteImageMetadata } from "./types.js";
|
|
18
18
|
import { getCookies } from "@steipete/sweet-cookie";
|
|
19
19
|
import { CHATGPT_URL } from "../browser/constants.js";
|
|
20
20
|
import { getCliVersion } from "../version.js";
|
|
21
21
|
import { getOracleHomeDir } from "../oracleHome.js";
|
|
22
22
|
import { cleanupStaleProfileState, readDevToolsPort, verifyDevToolsReachable, writeChromePid, writeDevToolsActivePort, } from "../browser/profileState.js";
|
|
23
23
|
import { normalizeChatgptUrl } from "../browser/utils.js";
|
|
24
|
-
import { computeFileSha256, sanitizeArtifactFilename, sanitizeArtifactMimeType, validateArtifactFile, } from "../browser/artifacts.js";
|
|
24
|
+
import { computeFileSha256, resolveSessionArtifactsDir, sanitizeArtifactFilename, sanitizeArtifactMimeType, validateArtifactFile, } from "../browser/artifacts.js";
|
|
25
25
|
const ARTIFACT_PROTOCOL_VERSION = 1;
|
|
26
26
|
const REMOTE_ARTIFACT_TTL_MS = 30 * 60 * 1000;
|
|
27
27
|
const ARTIFACT_CAPABILITIES = {
|
|
28
28
|
runCancellation: true,
|
|
29
29
|
deferredFallbackBundling: true,
|
|
30
30
|
artifactTransfer: true,
|
|
31
|
+
generatedImages: true,
|
|
31
32
|
artifactProtocolVersion: ARTIFACT_PROTOCOL_VERSION,
|
|
32
33
|
maxArtifactBytes: MAX_REMOTE_ARTIFACT_BYTES,
|
|
33
34
|
};
|
|
@@ -334,6 +335,9 @@ export async function createRemoteServer(options = {}, deps = {}) {
|
|
|
334
335
|
? payload.options.sessionId.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 32)
|
|
335
336
|
: "remote";
|
|
336
337
|
payload.options.sessionId = `${clientSession || "remote"}-${runId}`;
|
|
338
|
+
const hostImageOutputPath = payload.options.imageOutputRequested === true
|
|
339
|
+
? path.join(resolveSessionArtifactsDir(payload.options.sessionId), "generated.png")
|
|
340
|
+
: undefined;
|
|
337
341
|
if (browserTabCap !== undefined)
|
|
338
342
|
payload.browserConfig.maxConcurrentTabs = browserTabCap;
|
|
339
343
|
signal?.throwIfAborted();
|
|
@@ -362,6 +366,7 @@ export async function createRemoteServer(options = {}, deps = {}) {
|
|
|
362
366
|
heartbeatIntervalMs: payload.options.heartbeatIntervalMs,
|
|
363
367
|
verbose: payload.options.verbose,
|
|
364
368
|
sessionId: payload.options.sessionId,
|
|
369
|
+
generateImagePath: hostImageOutputPath,
|
|
365
370
|
followUpPrompts: payload.options.followUpPrompts,
|
|
366
371
|
});
|
|
367
372
|
signal?.throwIfAborted();
|
|
@@ -615,13 +620,14 @@ function remoteArtifactKey(runId, artifactId) {
|
|
|
615
620
|
async function registerRemoteArtifacts(params) {
|
|
616
621
|
pruneExpiredArtifacts(params.artifactRegistry);
|
|
617
622
|
const seen = new Set();
|
|
618
|
-
const
|
|
623
|
+
const transferableArtifacts = [
|
|
619
624
|
...(params.result.savedFiles ?? []),
|
|
620
|
-
...(params.result.
|
|
625
|
+
...(params.result.savedImages ?? []),
|
|
626
|
+
...(params.result.artifacts ?? []).filter((artifact) => artifact.kind === "file" || artifact.kind === "image"),
|
|
621
627
|
];
|
|
622
628
|
const descriptors = [];
|
|
623
629
|
const warnings = [];
|
|
624
|
-
for (const artifact of
|
|
630
|
+
for (const artifact of transferableArtifacts) {
|
|
625
631
|
if (!artifact?.path || seen.has(artifact.path)) {
|
|
626
632
|
continue;
|
|
627
633
|
}
|
|
@@ -630,7 +636,9 @@ async function registerRemoteArtifacts(params) {
|
|
|
630
636
|
const filename = sanitizeArtifactFilename(path.basename(artifact.path), "artifact.bin");
|
|
631
637
|
params.logger(`[serve] Skipping remote artifact descriptor: ${error instanceof Error ? error.message : String(error)}`);
|
|
632
638
|
warnings.push({
|
|
633
|
-
code:
|
|
639
|
+
code: artifact.kind === "image"
|
|
640
|
+
? "remote-image-registration-failed"
|
|
641
|
+
: "remote-artifact-registration-failed",
|
|
634
642
|
severity: "warning",
|
|
635
643
|
message: `Oracle captured the browser text response, but the bridge host could not prepare ${filename} for transfer. ` +
|
|
636
644
|
"Open the ChatGPT browser on the bridge host, download the ZIP/file shown in the current response, and copy it to a cloud-readable path.",
|
|
@@ -675,7 +683,12 @@ async function buildRemoteArtifactRegistration(runId, artifact) {
|
|
|
675
683
|
descriptor: {
|
|
676
684
|
artifactId: randomUUID(),
|
|
677
685
|
runId,
|
|
678
|
-
kind: "file",
|
|
686
|
+
kind: artifact.kind === "image" ? "image" : "file",
|
|
687
|
+
...(artifact.kind === "image"
|
|
688
|
+
? {
|
|
689
|
+
image: pickRemoteImageMetadata(artifact),
|
|
690
|
+
}
|
|
691
|
+
: {}),
|
|
679
692
|
filename,
|
|
680
693
|
mimeType,
|
|
681
694
|
byteSize: fileStat.size,
|
|
@@ -740,6 +753,7 @@ const CLIENT_BROWSER_CONFIG_FIELDS = [
|
|
|
740
753
|
"chatgptUrl",
|
|
741
754
|
"url",
|
|
742
755
|
"desiredModel",
|
|
756
|
+
"modelIsImplicitDefault",
|
|
743
757
|
"modelStrategy",
|
|
744
758
|
"thinkingTime",
|
|
745
759
|
"researchMode",
|
|
@@ -805,10 +819,37 @@ async function stageRemoteAttachments(payload, directory, defaultPrefix) {
|
|
|
805
819
|
}
|
|
806
820
|
// Return conversation identity and observed selection; keep process/profile details on the host.
|
|
807
821
|
function sanitizeResult(result, warnings = []) {
|
|
822
|
+
const hostArtifactPaths = [
|
|
823
|
+
...(result.savedFiles ?? []),
|
|
824
|
+
...(result.savedImages ?? []),
|
|
825
|
+
...(result.artifacts ?? []),
|
|
826
|
+
]
|
|
827
|
+
.map((artifact) => artifact.path)
|
|
828
|
+
.filter((artifactPath) => Boolean(artifactPath));
|
|
829
|
+
const savedImagePaths = [
|
|
830
|
+
...(result.savedImages ?? []),
|
|
831
|
+
...(result.artifacts ?? []).filter((artifact) => artifact.kind === "image"),
|
|
832
|
+
].map((artifact) => artifact.path);
|
|
833
|
+
const imageCount = new Set(savedImagePaths).size;
|
|
834
|
+
const sanitizeAnswer = (value) => {
|
|
835
|
+
let sanitized = value;
|
|
836
|
+
// Local save notices describe the host filesystem, not the client's transferred files.
|
|
837
|
+
for (const imagePath of savedImagePaths) {
|
|
838
|
+
sanitized = sanitized
|
|
839
|
+
?.split(` Saved to: ${imagePath}`)
|
|
840
|
+
.join("")
|
|
841
|
+
.split(` Saved ${imageCount} file(s) starting at: ${imagePath}`)
|
|
842
|
+
.join("");
|
|
843
|
+
}
|
|
844
|
+
for (const artifactPath of hostArtifactPaths) {
|
|
845
|
+
sanitized = sanitized?.split(artifactPath).join(path.basename(artifactPath));
|
|
846
|
+
}
|
|
847
|
+
return sanitized;
|
|
848
|
+
};
|
|
808
849
|
return {
|
|
809
|
-
answerText: result.answerText,
|
|
810
|
-
answerMarkdown: result.answerMarkdown,
|
|
811
|
-
answerHtml: result.answerHtml,
|
|
850
|
+
answerText: sanitizeAnswer(result.answerText) ?? "",
|
|
851
|
+
answerMarkdown: sanitizeAnswer(result.answerMarkdown) ?? "",
|
|
852
|
+
answerHtml: sanitizeAnswer(result.answerHtml),
|
|
812
853
|
tookMs: result.tookMs,
|
|
813
854
|
answerTokens: result.answerTokens,
|
|
814
855
|
answerChars: result.answerChars,
|
|
@@ -819,6 +860,7 @@ function sanitizeResult(result, warnings = []) {
|
|
|
819
860
|
tabUrl: result.tabUrl,
|
|
820
861
|
conversationId: result.conversationId,
|
|
821
862
|
promptSubmitted: result.promptSubmitted,
|
|
863
|
+
submittedPromptHash: result.submittedPromptHash,
|
|
822
864
|
warnings: warnings.length > 0 ? warnings : undefined,
|
|
823
865
|
chromePid: undefined,
|
|
824
866
|
chromePort: undefined,
|
package/dist/src/remote/types.js
CHANGED
|
@@ -1 +1,14 @@
|
|
|
1
1
|
export const MAX_REMOTE_ARTIFACT_BYTES = 512 * 1024 * 1024;
|
|
2
|
+
export function pickRemoteImageMetadata(image = {}) {
|
|
3
|
+
return {
|
|
4
|
+
...(Number.isSafeInteger(image.width) && Number(image.width) > 0
|
|
5
|
+
? { width: Number(image.width) }
|
|
6
|
+
: {}),
|
|
7
|
+
...(Number.isSafeInteger(image.height) && Number(image.height) > 0
|
|
8
|
+
? { height: Number(image.height) }
|
|
9
|
+
: {}),
|
|
10
|
+
...(typeof image.fileId === "string" && /^file[-_][a-z0-9_-]{1,200}$/i.test(image.fileId)
|
|
11
|
+
? { fileId: image.fileId }
|
|
12
|
+
: {}),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -304,7 +304,14 @@ export async function initializeSession(options, cwd, notifications, baseSlugOve
|
|
|
304
304
|
})),
|
|
305
305
|
cwd,
|
|
306
306
|
mode,
|
|
307
|
-
browser:
|
|
307
|
+
browser: mode === "browser"
|
|
308
|
+
? {
|
|
309
|
+
...(browserConfig ? { config: browserConfig } : {}),
|
|
310
|
+
runtime: { submittedPromptHash: null },
|
|
311
|
+
}
|
|
312
|
+
: browserConfig
|
|
313
|
+
? { config: browserConfig }
|
|
314
|
+
: undefined,
|
|
308
315
|
notifications,
|
|
309
316
|
options: {
|
|
310
317
|
prompt: options.prompt,
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@steipete/oracle",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.2",
|
|
4
4
|
"description": "CLI wrapper around OpenAI Responses API with GPT-5.6 Sol, GPT-5.6, 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://askoracle.sh",
|
|
@@ -70,17 +70,17 @@
|
|
|
70
70
|
"dotenv": "^17.4.2",
|
|
71
71
|
"fast-glob": "^3.3.3",
|
|
72
72
|
"gpt-tokenizer": "^4.0.0",
|
|
73
|
-
"inquirer": "14.2.
|
|
73
|
+
"inquirer": "14.2.2",
|
|
74
74
|
"json5": "^2.2.3",
|
|
75
75
|
"kleur": "^4.1.5",
|
|
76
76
|
"markdansi": "0.3.3",
|
|
77
|
-
"openai": "^7.
|
|
77
|
+
"openai": "^7.13.0",
|
|
78
78
|
"osc-progress": "^0.3.3",
|
|
79
79
|
"qs": "^6.16.0",
|
|
80
80
|
"shiki": "^4.4.3",
|
|
81
81
|
"toasted-notifier": "^10.1.0",
|
|
82
|
-
"tokentally": "^0.1.
|
|
83
|
-
"zod": "^4.
|
|
82
|
+
"tokentally": "^0.1.6",
|
|
83
|
+
"zod": "^4.6.1"
|
|
84
84
|
},
|
|
85
85
|
"devDependencies": {
|
|
86
86
|
"@anthropic-ai/tokenizer": "^0.0.4",
|
|
@@ -88,13 +88,13 @@
|
|
|
88
88
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
89
89
|
"@types/chrome-remote-interface": "^0.34.0",
|
|
90
90
|
"@types/inquirer": "^9.0.10",
|
|
91
|
-
"@types/node": "^26.
|
|
91
|
+
"@types/node": "^26.5.1",
|
|
92
92
|
"@vitest/coverage-v8": "5.0.0",
|
|
93
|
-
"devtools-protocol": "0.0.
|
|
93
|
+
"devtools-protocol": "0.0.1694333",
|
|
94
94
|
"es-toolkit": "^1.52.0",
|
|
95
95
|
"esbuild": "^0.28.2",
|
|
96
|
-
"oxfmt": "0.
|
|
97
|
-
"oxlint": "^1.
|
|
96
|
+
"oxfmt": "0.67.0",
|
|
97
|
+
"oxlint": "^1.82.0",
|
|
98
98
|
"puppeteer-core": "^25.10.0",
|
|
99
99
|
"tsx": "^4.23.13",
|
|
100
100
|
"typescript": "^7.0.2",
|
|
Binary file
|
|
Binary file
|