@steipete/oracle 0.17.2 → 0.17.3
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 +0 -0
- package/dist/bin/oracle-mcp.js +0 -0
- package/dist/bin/oracle.js +683 -0
- package/dist/docs-site/bridge.html +1 -17
- package/dist/docs-site/browser-mode.html +18 -26
- package/dist/docs-site/cli-reference.html +6 -6
- package/dist/docs-site/configuration.html +7 -33
- package/dist/docs-site/followup.html +9 -16
- package/dist/docs-site/gemini.html +6 -10
- package/dist/docs-site/index.html +7 -7
- package/dist/docs-site/install.html +1 -1
- package/dist/docs-site/manual-tests.html +2 -4
- package/dist/docs-site/mcp.html +5 -28
- package/dist/docs-site/mythical-pro-agents.html +10 -10
- package/dist/docs-site/openai-endpoints.html +1 -24
- package/dist/docs-site/quickstart.html +1 -1
- package/dist/docs-site/sessions.html +5 -6
- package/dist/docs-site/spec.html +1 -1
- package/dist/docs-site/windows-work.html +1 -2
- package/dist/docs-site/windows.html +1 -1
- package/dist/markdansi/types/index.js +4 -0
- package/dist/oracle/bin/oracle-cli.js +472 -0
- package/dist/oracle/src/browser/actions/assistantResponse.js +471 -0
- package/dist/oracle/src/browser/actions/attachments.js +82 -0
- package/dist/oracle/src/browser/actions/modelSelection.js +190 -0
- package/dist/oracle/src/browser/actions/navigation.js +75 -0
- package/dist/oracle/src/browser/actions/promptComposer.js +167 -0
- package/dist/oracle/src/browser/chromeLifecycle.js +104 -0
- package/dist/oracle/src/browser/config.js +33 -0
- package/dist/oracle/src/browser/constants.js +40 -0
- package/dist/oracle/src/browser/cookies.js +210 -0
- package/dist/oracle/src/browser/domDebug.js +36 -0
- package/dist/oracle/src/browser/index.js +331 -0
- package/dist/oracle/src/browser/pageActions.js +5 -0
- package/dist/oracle/src/browser/prompt.js +88 -0
- package/dist/oracle/src/browser/promptSummary.js +20 -0
- package/dist/oracle/src/browser/sessionRunner.js +80 -0
- package/dist/oracle/src/browser/types.js +1 -0
- package/dist/oracle/src/browser/utils.js +62 -0
- package/dist/oracle/src/browserMode.js +1 -0
- package/dist/oracle/src/cli/browserConfig.js +44 -0
- package/dist/oracle/src/cli/dryRun.js +59 -0
- package/dist/oracle/src/cli/engine.js +17 -0
- package/dist/oracle/src/cli/errorUtils.js +9 -0
- package/dist/oracle/src/cli/help.js +70 -0
- package/dist/oracle/src/cli/markdownRenderer.js +15 -0
- package/dist/oracle/src/cli/options.js +103 -0
- package/dist/oracle/src/cli/promptRequirement.js +14 -0
- package/dist/oracle/src/cli/rootAlias.js +30 -0
- package/dist/oracle/src/cli/sessionCommand.js +77 -0
- package/dist/oracle/src/cli/sessionDisplay.js +270 -0
- package/dist/oracle/src/cli/sessionRunner.js +94 -0
- package/dist/oracle/src/heartbeat.js +43 -0
- package/dist/oracle/src/oracle/client.js +48 -0
- package/dist/oracle/src/oracle/config.js +29 -0
- package/dist/oracle/src/oracle/errors.js +101 -0
- package/dist/oracle/src/oracle/files.js +220 -0
- package/dist/oracle/src/oracle/format.js +33 -0
- package/dist/oracle/src/oracle/fsAdapter.js +7 -0
- package/dist/oracle/src/oracle/oscProgress.js +60 -0
- package/dist/oracle/src/oracle/request.js +48 -0
- package/dist/oracle/src/oracle/run.js +444 -0
- package/dist/oracle/src/oracle/tokenStats.js +39 -0
- package/dist/oracle/src/oracle/types.js +1 -0
- package/dist/oracle/src/oracle.js +9 -0
- package/dist/oracle/src/sessionManager.js +205 -0
- package/dist/oracle/src/version.js +39 -0
- package/dist/scripts/chrome/browser-tools.js +295 -0
- package/dist/src/browser/actions/assistantResponse.js +71 -23
- package/dist/src/browser/actions/thinkingTime.js +16 -9
- package/dist/src/browser/chromeCookies.js +312 -0
- package/dist/src/browser/index.js +5 -1
- package/dist/src/browser/keytarShim.js +56 -0
- package/dist/src/browser/policies.js +4 -0
- package/dist/src/browser/profileSync.js +141 -0
- package/dist/src/browser/projectSourcesRunner.js +2 -2
- package/dist/src/browser/reattach.js +47 -35
- package/dist/src/browser/windowsCookies.js +219 -0
- package/dist/src/cli/browserConfig.js +8 -2
- package/dist/src/cli/browserDefaults.js +6 -1
- package/dist/src/cli/projectSources.js +8 -1
- package/dist/src/mcp/tools/consult.js +1 -1
- package/dist/vendor/oracle-notifier/OracleNotifier.app/Contents/CodeResources +0 -0
- package/dist/vendor/oracle-notifier/OracleNotifier.app/Contents/Info.plist +20 -0
- package/dist/vendor/oracle-notifier/OracleNotifier.app/Contents/MacOS/OracleNotifier +0 -0
- package/dist/vendor/oracle-notifier/OracleNotifier.app/Contents/Resources/OracleIcon.icns +0 -0
- package/dist/vendor/oracle-notifier/OracleNotifier.app/Contents/_CodeSignature/CodeResources +128 -0
- package/package.json +8 -8
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/CodeResources +0 -0
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/Info.plist +20 -0
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/MacOS/OracleNotifier +0 -0
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/Resources/OracleIcon.icns +0 -0
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/_CodeSignature/CodeResources +128 -0
|
@@ -12,6 +12,7 @@ import { cleanupStaleProfileState } from "./profileState.js";
|
|
|
12
12
|
import { readDevToolsActivePortInfo } from "./detect.js";
|
|
13
13
|
import { pickTarget, extractConversationIdFromUrl, buildConversationUrl, withTimeout, openConversationFromSidebar, openConversationFromSidebarWithRetry, waitForLocationChange, readConversationTurnIndex, buildPromptEchoMatcher, recoverPromptEcho, alignPromptEchoMarkdown, } from "./reattachHelpers.js";
|
|
14
14
|
import { waitForDeepResearchCompletion } from "./actions/deepResearch.js";
|
|
15
|
+
import { shouldSyncBrowserCookies } from "./policies.js";
|
|
15
16
|
export async function resumeBrowserSession(runtime, config, logger, deps = {}) {
|
|
16
17
|
const recoverSession = deps.recoverSession ??
|
|
17
18
|
(async (runtimeMeta, configMeta) => resumeBrowserSessionViaNewChrome(runtimeMeta, configMeta, logger, deps));
|
|
@@ -176,9 +177,37 @@ async function resumeBrowserSessionViaNewChrome(runtime, config, logger, deps) {
|
|
|
176
177
|
if (manualLogin) {
|
|
177
178
|
await mkdir(userDataDir, { recursive: true });
|
|
178
179
|
}
|
|
179
|
-
const
|
|
180
|
-
const
|
|
181
|
-
const
|
|
180
|
+
const launch = deps.launchChrome ?? launchChrome;
|
|
181
|
+
const connectToLaunchedChrome = deps.connectToChrome ?? connectToChrome;
|
|
182
|
+
const chrome = await launch(resolved, userDataDir, logger);
|
|
183
|
+
const chromeHost = chrome && typeof chrome === "object" && "host" in chrome && typeof chrome.host === "string"
|
|
184
|
+
? chrome.host
|
|
185
|
+
: "127.0.0.1";
|
|
186
|
+
const client = await connectToLaunchedChrome(chrome.port, logger, chromeHost);
|
|
187
|
+
const cleanup = async () => {
|
|
188
|
+
if (client && typeof client.close === "function") {
|
|
189
|
+
try {
|
|
190
|
+
await client.close();
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
// ignore
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (!resolved.keepBrowser) {
|
|
197
|
+
try {
|
|
198
|
+
await chrome.kill();
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
// ignore
|
|
202
|
+
}
|
|
203
|
+
if (manualLogin) {
|
|
204
|
+
await cleanupStaleProfileState(userDataDir, logger, { lockRemovalMode: "never" }).catch(() => undefined);
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
await rm(userDataDir, { recursive: true, force: true }).catch(() => undefined);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
};
|
|
182
211
|
const { Network, Page, Runtime, DOM, Target } = client;
|
|
183
212
|
if (Runtime?.enable) {
|
|
184
213
|
await Runtime.enable();
|
|
@@ -190,14 +219,21 @@ async function resumeBrowserSessionViaNewChrome(runtime, config, logger, deps) {
|
|
|
190
219
|
await positionChromeWindowOffscreen(client, logger);
|
|
191
220
|
}
|
|
192
221
|
let appliedCookies = 0;
|
|
193
|
-
if (
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
222
|
+
if (shouldSyncBrowserCookies(resolved, { manualLogin })) {
|
|
223
|
+
const sync = deps.syncCookies ?? syncCookies;
|
|
224
|
+
try {
|
|
225
|
+
appliedCookies = await sync(Network, resolved.url, resolved.chromeProfile, logger, {
|
|
226
|
+
allowErrors: resolved.allowCookieErrors,
|
|
227
|
+
filterNames: resolved.cookieNames ?? undefined,
|
|
228
|
+
inlineCookies: resolved.inlineCookies ?? undefined,
|
|
229
|
+
cookiePath: resolved.chromeCookiePath ?? undefined,
|
|
230
|
+
waitMs: resolved.cookieSyncWaitMs ?? 0,
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
await cleanup();
|
|
235
|
+
throw error;
|
|
236
|
+
}
|
|
201
237
|
}
|
|
202
238
|
await clearStaleChatGptConversationCookies(Network, Target, logger, {
|
|
203
239
|
preserveConversationIds: [
|
|
@@ -242,30 +278,6 @@ async function resumeBrowserSessionViaNewChrome(runtime, config, logger, deps) {
|
|
|
242
278
|
const waitForResponse = deps.waitForAssistantResponse ?? waitForAssistantResponse;
|
|
243
279
|
const captureMarkdown = deps.captureAssistantMarkdown ?? captureAssistantMarkdown;
|
|
244
280
|
const timeoutMs = resolved.timeoutMs ?? 120_000;
|
|
245
|
-
const cleanup = async () => {
|
|
246
|
-
if (client && typeof client.close === "function") {
|
|
247
|
-
try {
|
|
248
|
-
await client.close();
|
|
249
|
-
}
|
|
250
|
-
catch {
|
|
251
|
-
// ignore
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
if (!resolved.keepBrowser) {
|
|
255
|
-
try {
|
|
256
|
-
await chrome.kill();
|
|
257
|
-
}
|
|
258
|
-
catch {
|
|
259
|
-
// ignore
|
|
260
|
-
}
|
|
261
|
-
if (manualLogin) {
|
|
262
|
-
await cleanupStaleProfileState(userDataDir, logger, { lockRemovalMode: "never" }).catch(() => undefined);
|
|
263
|
-
}
|
|
264
|
-
else {
|
|
265
|
-
await rm(userDataDir, { recursive: true, force: true }).catch(() => undefined);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
};
|
|
269
281
|
const minTurnIndex = (await readPromptPreviewTurnIndex(Runtime, deps.promptPreview)) ??
|
|
270
282
|
(deps.promptPreview ? null : await readConversationTurnIndex(Runtime, logger));
|
|
271
283
|
if (resolved.researchMode === "deep") {
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import { existsSync, promises as fsp } from 'node:fs';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import sqlite3 from 'sqlite3';
|
|
7
|
+
import { createRequire } from 'node:module';
|
|
8
|
+
import { spawnSync } from 'node:child_process';
|
|
9
|
+
let cachedUnprotect = null;
|
|
10
|
+
function getUnprotectData() {
|
|
11
|
+
if (cachedUnprotect) {
|
|
12
|
+
return cachedUnprotect;
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
// win-dpapi is CommonJS; require it explicitly and support both named/default shapes.
|
|
16
|
+
const dpapiModule = createRequire(import.meta.url)('win-dpapi');
|
|
17
|
+
const unprotect = dpapiModule?.Dpapi?.unprotectData ??
|
|
18
|
+
dpapiModule?.default?.unprotectData ??
|
|
19
|
+
((_) => {
|
|
20
|
+
throw new Error('win-dpapi unprotectData not available');
|
|
21
|
+
});
|
|
22
|
+
cachedUnprotect = unprotect;
|
|
23
|
+
return unprotect;
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
if (process.platform !== 'win32') {
|
|
27
|
+
// On macOS/Linux we don't need DPAPI; return a function that makes misuse obvious.
|
|
28
|
+
cachedUnprotect = () => {
|
|
29
|
+
throw new Error('win-dpapi is unavailable on non-Windows platforms');
|
|
30
|
+
};
|
|
31
|
+
return cachedUnprotect;
|
|
32
|
+
}
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export async function loadWindowsCookies(dbPath, filterNames) {
|
|
37
|
+
if (process.platform !== 'win32') {
|
|
38
|
+
throw new Error('loadWindowsCookies is only supported on Windows');
|
|
39
|
+
}
|
|
40
|
+
const localStatePath = await locateLocalState(dbPath);
|
|
41
|
+
const cookiesCopy = await copyLockedFile(dbPath, 'Cookies'); // name the copy exactly "Cookies"
|
|
42
|
+
const cookiesDirForFallback = await ensureCookiesDirForFallback(cookiesCopy);
|
|
43
|
+
const localStateCopy = await copyLockedFile(localStatePath, 'Local State');
|
|
44
|
+
const aesKey = await extractWindowsAesKey(localStateCopy);
|
|
45
|
+
const rows = await readChromeCookiesDb(cookiesCopy, filterNames);
|
|
46
|
+
const cookies = [];
|
|
47
|
+
for (const row of rows) {
|
|
48
|
+
const enc = row.encrypted_value && row.encrypted_value.length > 0 ? row.encrypted_value : Buffer.from(row.value ?? '', 'utf8');
|
|
49
|
+
const decrypted = enc.length > 0 ? decryptCookie(enc, aesKey) : '';
|
|
50
|
+
cookies.push({
|
|
51
|
+
name: row.name,
|
|
52
|
+
value: decrypted,
|
|
53
|
+
domain: row.host_key?.startsWith('.') ? row.host_key.slice(1) : row.host_key,
|
|
54
|
+
path: row.path ?? '/',
|
|
55
|
+
expires: normalizeExpiration(row.expires_utc),
|
|
56
|
+
secure: Boolean(row.is_secure),
|
|
57
|
+
httpOnly: Boolean(row.is_httponly),
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
if (process.env.ORACLE_DEBUG_COOKIES === '1') {
|
|
61
|
+
// eslint-disable-next-line no-console
|
|
62
|
+
console.log(`[cookies] windows decrypt decoded ${cookies.length} cookies from ${cookiesCopy} (fallback dir ${cookiesDirForFallback})`);
|
|
63
|
+
}
|
|
64
|
+
return cookies.filter((c) => c.value);
|
|
65
|
+
}
|
|
66
|
+
function decryptCookie(value, aesKey) {
|
|
67
|
+
const prefix = value.slice(0, 3).toString();
|
|
68
|
+
// Chrome prefixes AES-GCM encrypted cookies with version markers like v10/v11/v20; treat all v** the same.
|
|
69
|
+
if (/^v\d{2}$/u.test(prefix)) {
|
|
70
|
+
const iv = value.slice(3, 15);
|
|
71
|
+
const tag = value.slice(value.length - 16);
|
|
72
|
+
const data = value.slice(15, value.length - 16);
|
|
73
|
+
const decipher = crypto.createDecipheriv('aes-256-gcm', aesKey, iv);
|
|
74
|
+
decipher.setAuthTag(tag);
|
|
75
|
+
const decrypted = Buffer.concat([decipher.update(data), decipher.final()]);
|
|
76
|
+
return decrypted.toString('utf8');
|
|
77
|
+
}
|
|
78
|
+
const unprotectData = getUnprotectData();
|
|
79
|
+
const unprotected = unprotectData(value, undefined, 'CurrentUser');
|
|
80
|
+
return Buffer.from(unprotected).toString('utf8');
|
|
81
|
+
}
|
|
82
|
+
async function locateLocalState(dbPath) {
|
|
83
|
+
// Prefer sibling Local State near the profile path; fall back to default location.
|
|
84
|
+
const guess = path.resolve(path.join(path.dirname(dbPath), '..', 'Local State'));
|
|
85
|
+
if (existsSync(guess))
|
|
86
|
+
return guess;
|
|
87
|
+
const localState = path.join(os.homedir(), 'AppData', 'Local', 'Google', 'Chrome', 'User Data', 'Local State');
|
|
88
|
+
if (existsSync(localState))
|
|
89
|
+
return localState;
|
|
90
|
+
throw new Error('Chrome Local State not found for AES key');
|
|
91
|
+
}
|
|
92
|
+
async function extractWindowsAesKey(localStatePath) {
|
|
93
|
+
const raw = await fs.readFile(localStatePath, 'utf8');
|
|
94
|
+
const state = JSON.parse(raw);
|
|
95
|
+
const encKeyB64 = state?.os_crypt?.encrypted_key;
|
|
96
|
+
if (!encKeyB64)
|
|
97
|
+
throw new Error('encrypted_key missing in Local State');
|
|
98
|
+
const encKey = Buffer.from(encKeyB64, 'base64');
|
|
99
|
+
const dpapiBlob = encKey.slice(5); // strip "DPAPI"
|
|
100
|
+
const unprotectData = getUnprotectData();
|
|
101
|
+
const unprotected = unprotectData(dpapiBlob, undefined, 'CurrentUser');
|
|
102
|
+
return Buffer.from(unprotected);
|
|
103
|
+
}
|
|
104
|
+
async function readChromeCookiesDb(dbPath, filterNames) {
|
|
105
|
+
const db = await openSqlite(dbPath);
|
|
106
|
+
const placeholders = filterNames && filterNames.size > 0 ? `AND name IN (${Array.from(filterNames).map(() => '?').join(',')})` : '';
|
|
107
|
+
const params = filterNames ? Array.from(filterNames) : [];
|
|
108
|
+
const sql = `SELECT name,value,encrypted_value,host_key,path,expires_utc,is_secure,is_httponly FROM cookies WHERE host_key LIKE '%chatgpt.com%' ${placeholders}`;
|
|
109
|
+
try {
|
|
110
|
+
return await allSqlite(db, sql, params);
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
db.close();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function openSqlite(dbPath) {
|
|
117
|
+
return new Promise((resolve, reject) => {
|
|
118
|
+
const db = new sqlite3.Database(dbPath, sqlite3.OPEN_READONLY, (err) => {
|
|
119
|
+
if (err)
|
|
120
|
+
reject(err);
|
|
121
|
+
else
|
|
122
|
+
resolve(db);
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
async function copyLockedFile(sourcePath, targetName) {
|
|
127
|
+
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'oracle-cookie-'));
|
|
128
|
+
const tempPath = targetName ? path.join(tempDir, targetName) : path.join(tempDir, path.basename(sourcePath));
|
|
129
|
+
const psScript = `
|
|
130
|
+
$src = '${sourcePath.replace(/'/g, "''")}'
|
|
131
|
+
$dst = '${tempPath.replace(/'/g, "''")}'
|
|
132
|
+
try {
|
|
133
|
+
$fs = [System.IO.File]::Open($src, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::ReadWrite)
|
|
134
|
+
$bytes = New-Object byte[] $fs.Length
|
|
135
|
+
$null = $fs.Read($bytes, 0, $fs.Length)
|
|
136
|
+
$fs.Close()
|
|
137
|
+
[System.IO.File]::WriteAllBytes($dst, $bytes)
|
|
138
|
+
exit 0
|
|
139
|
+
} catch {
|
|
140
|
+
exit 1
|
|
141
|
+
}
|
|
142
|
+
`;
|
|
143
|
+
const encoded = Buffer.from(psScript, 'utf16le').toString('base64');
|
|
144
|
+
const result = spawnSync('powershell.exe', ['-NoProfile', '-NonInteractive', '-EncodedCommand', encoded], {
|
|
145
|
+
timeout: 15000,
|
|
146
|
+
encoding: 'utf8',
|
|
147
|
+
});
|
|
148
|
+
if (result.status !== 0) {
|
|
149
|
+
// Fallback: best-effort normal copy
|
|
150
|
+
await fs.copyFile(sourcePath, tempPath);
|
|
151
|
+
}
|
|
152
|
+
if (process.env.ORACLE_DEBUG_COOKIES === '1') {
|
|
153
|
+
// eslint-disable-next-line no-console
|
|
154
|
+
console.log(`[cookies] copied locked file ${sourcePath} -> ${tempPath}`);
|
|
155
|
+
}
|
|
156
|
+
return tempPath;
|
|
157
|
+
}
|
|
158
|
+
// Create a directory containing a file named "Cookies" for chrome-cookies-secure fallback
|
|
159
|
+
export async function ensureCookiesDirForFallback(cookieFile) {
|
|
160
|
+
const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'oracle-cookies-secure-'));
|
|
161
|
+
const target = path.join(dir, 'Cookies');
|
|
162
|
+
await fs.copyFile(cookieFile, target);
|
|
163
|
+
return dir;
|
|
164
|
+
}
|
|
165
|
+
function allSqlite(db, sql, params) {
|
|
166
|
+
return new Promise((resolve, reject) => {
|
|
167
|
+
db.all(sql, params, (err, rows) => {
|
|
168
|
+
if (err)
|
|
169
|
+
reject(err);
|
|
170
|
+
else
|
|
171
|
+
resolve((rows ?? []));
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
function normalizeExpiration(expires) {
|
|
176
|
+
if (!expires || Number.isNaN(expires)) {
|
|
177
|
+
return undefined;
|
|
178
|
+
}
|
|
179
|
+
const value = Number(expires);
|
|
180
|
+
if (value <= 0)
|
|
181
|
+
return undefined;
|
|
182
|
+
if (value > 1_000_000_000_000) {
|
|
183
|
+
return Math.round(value / 1_000_000 - 11644473600);
|
|
184
|
+
}
|
|
185
|
+
if (value > 1_000_000_000) {
|
|
186
|
+
return Math.round(value / 1000);
|
|
187
|
+
}
|
|
188
|
+
return Math.round(value);
|
|
189
|
+
}
|
|
190
|
+
export async function materializeCookieFile(sourcePath) {
|
|
191
|
+
if (process.platform !== 'win32')
|
|
192
|
+
return sourcePath;
|
|
193
|
+
const resolved = await resolveDirectoryCandidate(sourcePath);
|
|
194
|
+
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'oracle-cookies-'));
|
|
195
|
+
const tempPath = path.join(tempDir, 'Cookies');
|
|
196
|
+
await fs.copyFile(resolved, tempPath);
|
|
197
|
+
return tempPath;
|
|
198
|
+
}
|
|
199
|
+
async function resolveDirectoryCandidate(inputPath) {
|
|
200
|
+
const stat = await fs.stat(inputPath).catch(() => null);
|
|
201
|
+
if (!stat?.isDirectory())
|
|
202
|
+
return inputPath;
|
|
203
|
+
const network = path.join(inputPath, 'Network', 'Cookies');
|
|
204
|
+
const direct = path.join(inputPath, 'Cookies');
|
|
205
|
+
if (await fileExists(network))
|
|
206
|
+
return network;
|
|
207
|
+
if (await fileExists(direct))
|
|
208
|
+
return direct;
|
|
209
|
+
return inputPath;
|
|
210
|
+
}
|
|
211
|
+
async function fileExists(candidate) {
|
|
212
|
+
try {
|
|
213
|
+
const stat = await fsp.stat(candidate);
|
|
214
|
+
return stat.isFile();
|
|
215
|
+
}
|
|
216
|
+
catch {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
@@ -161,14 +161,19 @@ export async function buildBrowserConfig(options) {
|
|
|
161
161
|
cookieSyncWaitMs: options.browserCookieWait
|
|
162
162
|
? parseBrowserDuration(options.browserCookieWait, "--browser-cookie-wait", 0)
|
|
163
163
|
: undefined,
|
|
164
|
-
cookieSync: options.browserNoCookieSync
|
|
164
|
+
cookieSync: options.browserNoCookieSync
|
|
165
|
+
? false
|
|
166
|
+
: options.browserManualLoginCookieSync === true
|
|
167
|
+
? true
|
|
168
|
+
: undefined,
|
|
165
169
|
cookieNames,
|
|
166
170
|
inlineCookies: inline?.cookies,
|
|
167
171
|
inlineCookiesSource: inline?.source ?? null,
|
|
168
|
-
headless:
|
|
172
|
+
headless: options.browserHeadless === true ? true : undefined,
|
|
169
173
|
keepBrowser: options.browserKeepBrowser ? true : undefined,
|
|
170
174
|
manualLogin: options.browserManualLogin === undefined ? undefined : options.browserManualLogin,
|
|
171
175
|
manualLoginProfileDir: options.browserManualLoginProfileDir ?? undefined,
|
|
176
|
+
manualLoginCookieSync: options.browserManualLoginCookieSync,
|
|
172
177
|
copyProfileSource: options.copyProfile ?? undefined,
|
|
173
178
|
hideWindow: options.browserHideWindow ? true : undefined,
|
|
174
179
|
desiredModel,
|
|
@@ -202,6 +207,7 @@ function validateAttachRunningOptions(options, { attachRunning, hasInlineCookies
|
|
|
202
207
|
options.browserChromeProfile ? "--browser-chrome-profile" : null,
|
|
203
208
|
options.browserCookiePath ? "--browser-cookie-path" : null,
|
|
204
209
|
options.browserNoCookieSync ? "--browser-no-cookie-sync" : null,
|
|
210
|
+
options.browserHeadless ? "--browser-headless" : null,
|
|
205
211
|
options.browserHideWindow ? "--browser-hide-window" : null,
|
|
206
212
|
options.browserKeepBrowser ? "--browser-keep-browser" : null,
|
|
207
213
|
options.browserManualLogin ? "--browser-manual-login" : null,
|
|
@@ -76,7 +76,7 @@ export function applyBrowserDefaultsFromConfig(options, config, getSource) {
|
|
|
76
76
|
if (isUnset("browserCookieWait") && typeof browser.cookieSyncWaitMs === "number") {
|
|
77
77
|
options.browserCookieWait = String(browser.cookieSyncWaitMs);
|
|
78
78
|
}
|
|
79
|
-
if (isUnset("browserHeadless") && browser.headless !== undefined) {
|
|
79
|
+
if (!attachRunningRequested && isUnset("browserHeadless") && browser.headless !== undefined) {
|
|
80
80
|
options.browserHeadless = browser.headless;
|
|
81
81
|
}
|
|
82
82
|
if (!attachRunningRequested && isUnset("browserHideWindow") && browser.hideWindow !== undefined) {
|
|
@@ -111,4 +111,9 @@ export function applyBrowserDefaultsFromConfig(options, config, getSource) {
|
|
|
111
111
|
browser.manualLoginProfileDir !== undefined) {
|
|
112
112
|
options.browserManualLoginProfileDir = browser.manualLoginProfileDir;
|
|
113
113
|
}
|
|
114
|
+
if (!attachRunningRequested &&
|
|
115
|
+
isUnset("browserManualLoginCookieSync") &&
|
|
116
|
+
browser.manualLoginCookieSync !== undefined) {
|
|
117
|
+
options.browserManualLoginCookieSync = browser.manualLoginCookieSync;
|
|
118
|
+
}
|
|
114
119
|
}
|
|
@@ -71,14 +71,21 @@ export async function buildProjectSourcesBrowserConfig({ options, projectUrl, co
|
|
|
71
71
|
envProfileDir ??
|
|
72
72
|
null)
|
|
73
73
|
: null;
|
|
74
|
+
const manualLoginCookieSync = flagConfig.manualLoginCookieSync ?? configuredBrowser.manualLoginCookieSync;
|
|
75
|
+
const cookieSync = flagConfig.cookieSync === false
|
|
76
|
+
? false
|
|
77
|
+
: manualLogin
|
|
78
|
+
? manualLoginCookieSync === true
|
|
79
|
+
: configuredBrowser.cookieSync;
|
|
74
80
|
return {
|
|
75
81
|
...configuredBrowser,
|
|
76
82
|
...flagConfig,
|
|
77
83
|
url: projectUrl,
|
|
78
84
|
chatgptUrl: projectUrl,
|
|
79
|
-
cookieSync
|
|
85
|
+
cookieSync,
|
|
80
86
|
manualLogin,
|
|
81
87
|
manualLoginProfileDir,
|
|
88
|
+
manualLoginCookieSync,
|
|
82
89
|
desiredModel: null,
|
|
83
90
|
modelStrategy: "ignore",
|
|
84
91
|
researchMode: "off",
|
|
@@ -271,7 +271,7 @@ export function buildConsultBrowserConfig({ userConfig, env, runModel, inputMode
|
|
|
271
271
|
...configuredBrowser,
|
|
272
272
|
url: configuredUrl,
|
|
273
273
|
chatgptUrl: configuredUrl,
|
|
274
|
-
cookieSync: !manualLogin,
|
|
274
|
+
cookieSync: !manualLogin || configuredBrowser.manualLoginCookieSync === true,
|
|
275
275
|
headless: configuredBrowser.headless ?? false,
|
|
276
276
|
hideWindow: configuredBrowser.hideWindow ?? false,
|
|
277
277
|
keepBrowser: browserKeepBrowser ?? configuredBrowser.keepBrowser ?? false,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>CFBundleIdentifier</key>
|
|
6
|
+
<string>com.steipete.oracle.notifier</string>
|
|
7
|
+
<key>CFBundleName</key>
|
|
8
|
+
<string>OracleNotifier</string>
|
|
9
|
+
<key>CFBundleDisplayName</key>
|
|
10
|
+
<string>Oracle Notifier</string>
|
|
11
|
+
<key>CFBundleExecutable</key>
|
|
12
|
+
<string>OracleNotifier</string>
|
|
13
|
+
<key>CFBundleIconFile</key>
|
|
14
|
+
<string>OracleIcon</string>
|
|
15
|
+
<key>CFBundlePackageType</key>
|
|
16
|
+
<string>APPL</string>
|
|
17
|
+
<key>LSMinimumSystemVersion</key>
|
|
18
|
+
<string>13.0</string>
|
|
19
|
+
</dict>
|
|
20
|
+
</plist>
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>files</key>
|
|
6
|
+
<dict>
|
|
7
|
+
<key>Resources/OracleIcon.icns</key>
|
|
8
|
+
<data>
|
|
9
|
+
edUHAMetayIv3xtc3Vb92VXRLfM=
|
|
10
|
+
</data>
|
|
11
|
+
</dict>
|
|
12
|
+
<key>files2</key>
|
|
13
|
+
<dict>
|
|
14
|
+
<key>Resources/OracleIcon.icns</key>
|
|
15
|
+
<dict>
|
|
16
|
+
<key>hash2</key>
|
|
17
|
+
<data>
|
|
18
|
+
AVPJK/6w6IOsDLmZTW4hL+Za+/4wHMxZiIp0t6m3NRA=
|
|
19
|
+
</data>
|
|
20
|
+
</dict>
|
|
21
|
+
</dict>
|
|
22
|
+
<key>rules</key>
|
|
23
|
+
<dict>
|
|
24
|
+
<key>^Resources/</key>
|
|
25
|
+
<true/>
|
|
26
|
+
<key>^Resources/.*\.lproj/</key>
|
|
27
|
+
<dict>
|
|
28
|
+
<key>optional</key>
|
|
29
|
+
<true/>
|
|
30
|
+
<key>weight</key>
|
|
31
|
+
<real>1000</real>
|
|
32
|
+
</dict>
|
|
33
|
+
<key>^Resources/.*\.lproj/locversion.plist$</key>
|
|
34
|
+
<dict>
|
|
35
|
+
<key>omit</key>
|
|
36
|
+
<true/>
|
|
37
|
+
<key>weight</key>
|
|
38
|
+
<real>1100</real>
|
|
39
|
+
</dict>
|
|
40
|
+
<key>^Resources/Base\.lproj/</key>
|
|
41
|
+
<dict>
|
|
42
|
+
<key>weight</key>
|
|
43
|
+
<real>1010</real>
|
|
44
|
+
</dict>
|
|
45
|
+
<key>^version.plist$</key>
|
|
46
|
+
<true/>
|
|
47
|
+
</dict>
|
|
48
|
+
<key>rules2</key>
|
|
49
|
+
<dict>
|
|
50
|
+
<key>.*\.dSYM($|/)</key>
|
|
51
|
+
<dict>
|
|
52
|
+
<key>weight</key>
|
|
53
|
+
<real>11</real>
|
|
54
|
+
</dict>
|
|
55
|
+
<key>^(.*/)?\.DS_Store$</key>
|
|
56
|
+
<dict>
|
|
57
|
+
<key>omit</key>
|
|
58
|
+
<true/>
|
|
59
|
+
<key>weight</key>
|
|
60
|
+
<real>2000</real>
|
|
61
|
+
</dict>
|
|
62
|
+
<key>^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/</key>
|
|
63
|
+
<dict>
|
|
64
|
+
<key>nested</key>
|
|
65
|
+
<true/>
|
|
66
|
+
<key>weight</key>
|
|
67
|
+
<real>10</real>
|
|
68
|
+
</dict>
|
|
69
|
+
<key>^.*</key>
|
|
70
|
+
<true/>
|
|
71
|
+
<key>^Info\.plist$</key>
|
|
72
|
+
<dict>
|
|
73
|
+
<key>omit</key>
|
|
74
|
+
<true/>
|
|
75
|
+
<key>weight</key>
|
|
76
|
+
<real>20</real>
|
|
77
|
+
</dict>
|
|
78
|
+
<key>^PkgInfo$</key>
|
|
79
|
+
<dict>
|
|
80
|
+
<key>omit</key>
|
|
81
|
+
<true/>
|
|
82
|
+
<key>weight</key>
|
|
83
|
+
<real>20</real>
|
|
84
|
+
</dict>
|
|
85
|
+
<key>^Resources/</key>
|
|
86
|
+
<dict>
|
|
87
|
+
<key>weight</key>
|
|
88
|
+
<real>20</real>
|
|
89
|
+
</dict>
|
|
90
|
+
<key>^Resources/.*\.lproj/</key>
|
|
91
|
+
<dict>
|
|
92
|
+
<key>optional</key>
|
|
93
|
+
<true/>
|
|
94
|
+
<key>weight</key>
|
|
95
|
+
<real>1000</real>
|
|
96
|
+
</dict>
|
|
97
|
+
<key>^Resources/.*\.lproj/locversion.plist$</key>
|
|
98
|
+
<dict>
|
|
99
|
+
<key>omit</key>
|
|
100
|
+
<true/>
|
|
101
|
+
<key>weight</key>
|
|
102
|
+
<real>1100</real>
|
|
103
|
+
</dict>
|
|
104
|
+
<key>^Resources/Base\.lproj/</key>
|
|
105
|
+
<dict>
|
|
106
|
+
<key>weight</key>
|
|
107
|
+
<real>1010</real>
|
|
108
|
+
</dict>
|
|
109
|
+
<key>^[^/]+$</key>
|
|
110
|
+
<dict>
|
|
111
|
+
<key>nested</key>
|
|
112
|
+
<true/>
|
|
113
|
+
<key>weight</key>
|
|
114
|
+
<real>10</real>
|
|
115
|
+
</dict>
|
|
116
|
+
<key>^embedded\.provisionprofile$</key>
|
|
117
|
+
<dict>
|
|
118
|
+
<key>weight</key>
|
|
119
|
+
<real>20</real>
|
|
120
|
+
</dict>
|
|
121
|
+
<key>^version\.plist$</key>
|
|
122
|
+
<dict>
|
|
123
|
+
<key>weight</key>
|
|
124
|
+
<real>20</real>
|
|
125
|
+
</dict>
|
|
126
|
+
</dict>
|
|
127
|
+
</dict>
|
|
128
|
+
</plist>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@steipete/oracle",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.3",
|
|
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",
|
|
@@ -77,9 +77,9 @@
|
|
|
77
77
|
"openai": "^7.4.0",
|
|
78
78
|
"osc-progress": "^0.3.2",
|
|
79
79
|
"qs": "^6.15.3",
|
|
80
|
-
"shiki": "^4.4.
|
|
80
|
+
"shiki": "^4.4.2",
|
|
81
81
|
"toasted-notifier": "^10.1.0",
|
|
82
|
-
"tokentally": "^0.1.
|
|
82
|
+
"tokentally": "^0.1.3",
|
|
83
83
|
"zod": "^4.4.3"
|
|
84
84
|
},
|
|
85
85
|
"devDependencies": {
|
|
@@ -90,11 +90,11 @@
|
|
|
90
90
|
"@vitest/coverage-v8": "4.1.10",
|
|
91
91
|
"devtools-protocol": "0.0.1676105",
|
|
92
92
|
"es-toolkit": "^1.50.0",
|
|
93
|
-
"esbuild": "^0.28.
|
|
94
|
-
"oxfmt": "0.
|
|
95
|
-
"oxlint": "^1.
|
|
93
|
+
"esbuild": "^0.28.1",
|
|
94
|
+
"oxfmt": "0.62.0",
|
|
95
|
+
"oxlint": "^1.77.0",
|
|
96
96
|
"puppeteer-core": "^25.5.0",
|
|
97
|
-
"tsx": "^4.23.
|
|
97
|
+
"tsx": "^4.23.11",
|
|
98
98
|
"typescript": "^7.0.2",
|
|
99
99
|
"vitest": "^4.1.10"
|
|
100
100
|
},
|
|
@@ -109,5 +109,5 @@
|
|
|
109
109
|
"engines": {
|
|
110
110
|
"node": ">=24"
|
|
111
111
|
},
|
|
112
|
-
"packageManager": "pnpm@
|
|
112
|
+
"packageManager": "pnpm@11.20.0"
|
|
113
113
|
}
|
|
Binary file
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>CFBundleIdentifier</key>
|
|
6
|
+
<string>com.steipete.oracle.notifier</string>
|
|
7
|
+
<key>CFBundleName</key>
|
|
8
|
+
<string>OracleNotifier</string>
|
|
9
|
+
<key>CFBundleDisplayName</key>
|
|
10
|
+
<string>Oracle Notifier</string>
|
|
11
|
+
<key>CFBundleExecutable</key>
|
|
12
|
+
<string>OracleNotifier</string>
|
|
13
|
+
<key>CFBundleIconFile</key>
|
|
14
|
+
<string>OracleIcon</string>
|
|
15
|
+
<key>CFBundlePackageType</key>
|
|
16
|
+
<string>APPL</string>
|
|
17
|
+
<key>LSMinimumSystemVersion</key>
|
|
18
|
+
<string>13.0</string>
|
|
19
|
+
</dict>
|
|
20
|
+
</plist>
|