@steipete/oracle 0.8.6 → 0.10.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/LICENSE +1 -1
- package/README.md +130 -45
- package/dist/bin/oracle-cli.js +613 -379
- package/dist/bin/oracle-mcp.js +2 -2
- package/dist/bin/oracle.js +165 -279
- package/dist/scripts/agent-send.js +31 -31
- package/dist/scripts/check.js +6 -6
- package/dist/scripts/debug/extract-chatgpt-response.js +10 -10
- package/dist/scripts/docs-list.js +30 -30
- package/dist/scripts/git-policy.js +25 -23
- package/dist/scripts/run-cli.js +8 -8
- package/dist/scripts/runner.js +203 -195
- package/dist/scripts/test-browser.js +21 -18
- package/dist/scripts/test-remote-chrome.js +20 -20
- package/dist/src/bridge/connection.js +18 -18
- package/dist/src/bridge/userConfigFile.js +7 -7
- package/dist/src/browser/actions/assistantResponse.js +149 -101
- package/dist/src/browser/actions/attachmentDataTransfer.js +49 -47
- package/dist/src/browser/actions/attachments.js +246 -150
- package/dist/src/browser/actions/domEvents.js +2 -2
- package/dist/src/browser/actions/modelSelection.js +314 -104
- package/dist/src/browser/actions/navigation.js +161 -136
- package/dist/src/browser/actions/promptComposer.js +100 -64
- package/dist/src/browser/actions/remoteFileTransfer.js +10 -10
- package/dist/src/browser/actions/thinkingTime.js +207 -110
- package/dist/src/browser/chromeLifecycle.js +62 -60
- package/dist/src/browser/config.js +34 -15
- package/dist/src/browser/constants.js +17 -12
- package/dist/src/browser/cookies.js +19 -19
- package/dist/src/browser/detect.js +62 -62
- package/dist/src/browser/domDebug.js +1 -1
- package/dist/src/browser/index.js +452 -303
- package/dist/src/browser/modelStrategy.js +1 -1
- package/dist/src/browser/pageActions.js +5 -5
- package/dist/src/browser/policies.js +16 -13
- package/dist/src/browser/profileState.js +44 -39
- package/dist/src/browser/prompt.js +72 -42
- package/dist/src/browser/promptSummary.js +5 -5
- package/dist/src/browser/providerDomFlow.js +17 -0
- package/dist/src/browser/providers/chatgptDomProvider.js +49 -0
- package/dist/src/browser/providers/geminiDeepThinkDomProvider.js +254 -0
- package/dist/src/browser/providers/index.js +2 -0
- package/dist/src/browser/reattach.js +67 -34
- package/dist/src/browser/reattachHelpers.js +31 -26
- package/dist/src/browser/sessionRunner.js +37 -25
- package/dist/src/browser/utils.js +9 -9
- package/dist/src/browserMode.js +1 -1
- package/dist/src/cli/bridge/claudeConfig.js +16 -16
- package/dist/src/cli/bridge/client.js +28 -20
- package/dist/src/cli/bridge/codexConfig.js +16 -16
- package/dist/src/cli/bridge/doctor.js +47 -39
- package/dist/src/cli/bridge/host.js +58 -56
- package/dist/src/cli/browserConfig.js +65 -45
- package/dist/src/cli/browserDefaults.js +27 -26
- package/dist/src/cli/bundleWarnings.js +1 -1
- package/dist/src/cli/clipboard.js +11 -2
- package/dist/src/cli/detach.js +7 -4
- package/dist/src/cli/dryRun.js +29 -25
- package/dist/src/cli/duplicatePromptGuard.js +3 -3
- package/dist/src/cli/engine.js +9 -9
- package/dist/src/cli/errorUtils.js +1 -1
- package/dist/src/cli/fileSize.js +11 -0
- package/dist/src/cli/format.js +2 -2
- package/dist/src/cli/help.js +28 -28
- package/dist/src/cli/hiddenAliases.js +3 -3
- package/dist/src/cli/markdownBundle.js +12 -8
- package/dist/src/cli/markdownRenderer.js +15 -15
- package/dist/src/cli/notifier.js +77 -67
- package/dist/src/cli/options.js +145 -87
- package/dist/src/cli/oscUtils.js +1 -1
- package/dist/src/cli/promptRequirement.js +2 -2
- package/dist/src/cli/renderOutput.js +1 -1
- package/dist/src/cli/rootAlias.js +1 -1
- package/dist/src/cli/runOptions.js +37 -25
- package/dist/src/cli/sessionCommand.js +31 -21
- package/dist/src/cli/sessionDisplay.js +182 -79
- package/dist/src/cli/sessionLineage.js +60 -0
- package/dist/src/cli/sessionRunner.js +118 -90
- package/dist/src/cli/sessionTable.js +28 -24
- package/dist/src/cli/stdin.js +22 -0
- package/dist/src/cli/tagline.js +121 -124
- package/dist/src/cli/tui/index.js +140 -127
- package/dist/src/cli/writeOutputPath.js +5 -5
- package/dist/src/config.js +7 -7
- package/dist/src/gemini-web/browserSessionManager.js +80 -0
- package/dist/src/gemini-web/client.js +81 -64
- package/dist/src/gemini-web/executionMode.js +16 -0
- package/dist/src/gemini-web/executor.js +327 -169
- package/dist/src/gemini-web/index.js +1 -1
- package/dist/src/mcp/server.js +16 -12
- package/dist/src/mcp/tools/consult.js +81 -64
- package/dist/src/mcp/tools/sessionResources.js +12 -12
- package/dist/src/mcp/tools/sessions.js +26 -17
- package/dist/src/mcp/types.js +5 -5
- package/dist/src/mcp/utils.js +15 -7
- package/dist/src/oracle/background.js +15 -15
- package/dist/src/oracle/claude.js +53 -25
- package/dist/src/oracle/client.js +84 -46
- package/dist/src/oracle/config.js +124 -58
- package/dist/src/oracle/errors.js +38 -38
- package/dist/src/oracle/files.js +69 -45
- package/dist/src/oracle/finishLine.js +10 -8
- package/dist/src/oracle/format.js +3 -3
- package/dist/src/oracle/gemini.js +37 -30
- package/dist/src/oracle/logging.js +7 -7
- package/dist/src/oracle/markdown.js +28 -28
- package/dist/src/oracle/modelResolver.js +16 -16
- package/dist/src/oracle/multiModelRunner.js +12 -12
- package/dist/src/oracle/oscProgress.js +8 -8
- package/dist/src/oracle/promptAssembly.js +6 -3
- package/dist/src/oracle/request.js +23 -15
- package/dist/src/oracle/run.js +172 -140
- package/dist/src/oracle/runUtils.js +8 -5
- package/dist/src/oracle/tokenEstimate.js +6 -6
- package/dist/src/oracle/tokenStats.js +5 -5
- package/dist/src/oracle/tokenStringifier.js +5 -5
- package/dist/src/oracle.js +12 -12
- package/dist/src/oracleHome.js +3 -3
- package/dist/src/remote/client.js +25 -25
- package/dist/src/remote/health.js +20 -20
- package/dist/src/remote/remoteServiceConfig.js +9 -9
- package/dist/src/remote/server.js +129 -118
- package/dist/src/sessionManager.js +81 -75
- package/dist/src/sessionStore.js +3 -3
- package/dist/src/version.js +10 -10
- package/dist/vendor/oracle-notifier/OracleNotifier.app/Contents/CodeResources +0 -0
- package/dist/vendor/oracle-notifier/OracleNotifier.app/Contents/MacOS/OracleNotifier +0 -0
- package/dist/vendor/oracle-notifier/README.md +2 -0
- package/package.json +69 -65
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/CodeResources +0 -0
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/MacOS/OracleNotifier +0 -0
- package/vendor/oracle-notifier/README.md +2 -0
- package/dist/markdansi/types/index.js +0 -4
- package/dist/oracle/bin/oracle-cli.js +0 -472
- package/dist/oracle/src/browser/actions/assistantResponse.js +0 -471
- package/dist/oracle/src/browser/actions/attachments.js +0 -82
- package/dist/oracle/src/browser/actions/modelSelection.js +0 -190
- package/dist/oracle/src/browser/actions/navigation.js +0 -75
- package/dist/oracle/src/browser/actions/promptComposer.js +0 -167
- package/dist/oracle/src/browser/chromeLifecycle.js +0 -104
- package/dist/oracle/src/browser/config.js +0 -33
- package/dist/oracle/src/browser/constants.js +0 -40
- package/dist/oracle/src/browser/cookies.js +0 -210
- package/dist/oracle/src/browser/domDebug.js +0 -36
- package/dist/oracle/src/browser/index.js +0 -331
- package/dist/oracle/src/browser/pageActions.js +0 -5
- package/dist/oracle/src/browser/prompt.js +0 -88
- package/dist/oracle/src/browser/promptSummary.js +0 -20
- package/dist/oracle/src/browser/sessionRunner.js +0 -80
- package/dist/oracle/src/browser/utils.js +0 -62
- package/dist/oracle/src/browserMode.js +0 -1
- package/dist/oracle/src/cli/browserConfig.js +0 -44
- package/dist/oracle/src/cli/dryRun.js +0 -59
- package/dist/oracle/src/cli/engine.js +0 -17
- package/dist/oracle/src/cli/errorUtils.js +0 -9
- package/dist/oracle/src/cli/help.js +0 -70
- package/dist/oracle/src/cli/markdownRenderer.js +0 -15
- package/dist/oracle/src/cli/options.js +0 -103
- package/dist/oracle/src/cli/promptRequirement.js +0 -14
- package/dist/oracle/src/cli/rootAlias.js +0 -30
- package/dist/oracle/src/cli/sessionCommand.js +0 -77
- package/dist/oracle/src/cli/sessionDisplay.js +0 -270
- package/dist/oracle/src/cli/sessionRunner.js +0 -94
- package/dist/oracle/src/heartbeat.js +0 -43
- package/dist/oracle/src/oracle/client.js +0 -48
- package/dist/oracle/src/oracle/config.js +0 -29
- package/dist/oracle/src/oracle/errors.js +0 -101
- package/dist/oracle/src/oracle/files.js +0 -220
- package/dist/oracle/src/oracle/format.js +0 -33
- package/dist/oracle/src/oracle/fsAdapter.js +0 -7
- package/dist/oracle/src/oracle/oscProgress.js +0 -60
- package/dist/oracle/src/oracle/request.js +0 -48
- package/dist/oracle/src/oracle/run.js +0 -444
- package/dist/oracle/src/oracle/tokenStats.js +0 -39
- package/dist/oracle/src/oracle/types.js +0 -1
- package/dist/oracle/src/oracle.js +0 -9
- package/dist/oracle/src/sessionManager.js +0 -205
- package/dist/oracle/src/version.js +0 -39
- package/dist/scripts/chrome/browser-tools.js +0 -295
- package/dist/src/browser/profileSync.js +0 -141
- /package/dist/{oracle/src/browser/types.js → src/gemini-web/executionClients.js} +0 -0
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
import chalk from
|
|
2
|
-
import inquirer from
|
|
3
|
-
import kleur from
|
|
4
|
-
import path from
|
|
5
|
-
import os from
|
|
6
|
-
import fs from
|
|
7
|
-
import { DEFAULT_MODEL, MODEL_CONFIGS } from
|
|
8
|
-
import { renderMarkdownAnsi } from
|
|
9
|
-
import { sessionStore, pruneOldSessions } from
|
|
10
|
-
import { performSessionRun } from
|
|
11
|
-
import { MAX_RENDER_BYTES, trimBeforeFirstAnswer } from
|
|
12
|
-
import { formatSessionTableHeader, formatSessionTableRow } from
|
|
13
|
-
import { buildBrowserConfig, resolveBrowserModelLabel } from
|
|
14
|
-
import { resolveNotificationSettings } from
|
|
15
|
-
import { loadUserConfig } from
|
|
16
|
-
import {
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import inquirer from "inquirer";
|
|
3
|
+
import kleur from "kleur";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import os from "node:os";
|
|
6
|
+
import fs from "node:fs/promises";
|
|
7
|
+
import { DEFAULT_MODEL, MODEL_CONFIGS, } from "../../oracle.js";
|
|
8
|
+
import { renderMarkdownAnsi } from "../markdownRenderer.js";
|
|
9
|
+
import { sessionStore, pruneOldSessions } from "../../sessionStore.js";
|
|
10
|
+
import { performSessionRun } from "../sessionRunner.js";
|
|
11
|
+
import { MAX_RENDER_BYTES, trimBeforeFirstAnswer } from "../sessionDisplay.js";
|
|
12
|
+
import { formatSessionTableHeader, formatSessionTableRow } from "../sessionTable.js";
|
|
13
|
+
import { buildBrowserConfig, resolveBrowserModelLabel } from "../browserConfig.js";
|
|
14
|
+
import { resolveNotificationSettings } from "../notifier.js";
|
|
15
|
+
import { loadUserConfig } from "../../config.js";
|
|
16
|
+
import { resolveConfiguredMaxFileSizeBytes } from "../fileSize.js";
|
|
17
|
+
import { formatTokenCount } from "../../oracle/runUtils.js";
|
|
17
18
|
const isTty = () => Boolean(process.stdout.isTTY && chalk.level > 0);
|
|
18
19
|
const dim = (text) => (isTty() ? kleur.dim(text) : text);
|
|
19
20
|
const RECENT_WINDOW_HOURS = 24;
|
|
@@ -25,20 +26,20 @@ export async function launchTui({ version, printIntro = true }) {
|
|
|
25
26
|
let exitMessageShown = false;
|
|
26
27
|
if (printIntro) {
|
|
27
28
|
if (rich) {
|
|
28
|
-
console.log(chalk.bold(
|
|
29
|
+
console.log(chalk.bold("🧿 oracle"), `${version}`, dim("— Whispering your tokens to the silicon sage"));
|
|
29
30
|
}
|
|
30
31
|
else {
|
|
31
32
|
console.log(`🧿 oracle ${version} — Whispering your tokens to the silicon sage`);
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
|
-
console.log(
|
|
35
|
+
console.log("");
|
|
35
36
|
let showingOlder = false;
|
|
36
37
|
for (;;) {
|
|
37
38
|
const { recent, older, olderTotal } = await fetchSessionBuckets();
|
|
38
39
|
const choices = [];
|
|
39
40
|
const headerLabel = formatSessionTableHeader(isTty());
|
|
40
41
|
// Start with a selectable row so focus never lands on a separator
|
|
41
|
-
choices.push({ name: chalk.bold.green(
|
|
42
|
+
choices.push({ name: chalk.bold.green("ask oracle"), value: "__ask__" });
|
|
42
43
|
if (!showingOlder) {
|
|
43
44
|
if (recent.length > 0) {
|
|
44
45
|
choices.push(new inquirer.Separator(headerLabel));
|
|
@@ -54,22 +55,22 @@ export async function launchTui({ version, printIntro = true }) {
|
|
|
54
55
|
choices.push(new inquirer.Separator(headerLabel));
|
|
55
56
|
choices.push(...older.map(toSessionChoice));
|
|
56
57
|
}
|
|
57
|
-
choices.push(new inquirer.Separator(
|
|
58
|
-
choices.push(new inquirer.Separator(
|
|
59
|
-
choices.push({ name: chalk.bold.green(
|
|
58
|
+
choices.push(new inquirer.Separator(" "));
|
|
59
|
+
choices.push(new inquirer.Separator("Actions"));
|
|
60
|
+
choices.push({ name: chalk.bold.green("ask oracle"), value: "__ask__" });
|
|
60
61
|
if (!showingOlder && olderTotal > 0) {
|
|
61
|
-
choices.push({ name:
|
|
62
|
+
choices.push({ name: "Older page", value: "__older__" });
|
|
62
63
|
}
|
|
63
64
|
else {
|
|
64
|
-
choices.push({ name:
|
|
65
|
+
choices.push({ name: "Newer (recent)", value: "__reset__" });
|
|
65
66
|
}
|
|
66
|
-
choices.push({ name:
|
|
67
|
+
choices.push({ name: "Exit", value: "__exit__" });
|
|
67
68
|
const selection = await new Promise((resolve) => {
|
|
68
69
|
const prompt = inquirer.prompt([
|
|
69
70
|
{
|
|
70
|
-
name:
|
|
71
|
-
type:
|
|
72
|
-
message:
|
|
71
|
+
name: "selection",
|
|
72
|
+
type: "select",
|
|
73
|
+
message: "Select a session or action",
|
|
73
74
|
choices,
|
|
74
75
|
pageSize: 16,
|
|
75
76
|
loop: false,
|
|
@@ -80,40 +81,40 @@ export async function launchTui({ version, printIntro = true }) {
|
|
|
80
81
|
.catch((error) => {
|
|
81
82
|
pagingFailures += 1;
|
|
82
83
|
const message = error instanceof Error ? error.message : String(error);
|
|
83
|
-
if (message.includes(
|
|
84
|
-
console.log(chalk.green(
|
|
84
|
+
if (message.includes("SIGINT") || message.includes("force closed the prompt")) {
|
|
85
|
+
console.log(chalk.green("🧿 Closing the book. See you next prompt."));
|
|
85
86
|
exitMessageShown = true;
|
|
86
|
-
resolve(
|
|
87
|
+
resolve("__exit__");
|
|
87
88
|
return;
|
|
88
89
|
}
|
|
89
|
-
console.error(chalk.red(
|
|
90
|
-
if (message.includes(
|
|
91
|
-
console.error(chalk.red(
|
|
92
|
-
resolve(
|
|
90
|
+
console.error(chalk.red("Paging failed; returning to recent list."), message);
|
|
91
|
+
if (message.includes("setRawMode") || message.includes("EIO") || pagingFailures >= 3) {
|
|
92
|
+
console.error(chalk.red("Terminal input unavailable; exiting TUI."), dim("Try `stty sane` then rerun oracle, or use `oracle recent`."));
|
|
93
|
+
resolve("__exit__");
|
|
93
94
|
return;
|
|
94
95
|
}
|
|
95
|
-
resolve(
|
|
96
|
+
resolve("__reset__");
|
|
96
97
|
});
|
|
97
98
|
});
|
|
98
|
-
if (process.env.ORACLE_DEBUG_TUI ===
|
|
99
|
+
if (process.env.ORACLE_DEBUG_TUI === "1") {
|
|
99
100
|
console.error(`[tui] selection=${JSON.stringify(selection)}`);
|
|
100
101
|
}
|
|
101
102
|
pagingFailures = 0;
|
|
102
|
-
if (selection ===
|
|
103
|
+
if (selection === "__exit__") {
|
|
103
104
|
if (!exitMessageShown) {
|
|
104
|
-
console.log(chalk.green(
|
|
105
|
+
console.log(chalk.green("🧿 Closing the book. See you next prompt."));
|
|
105
106
|
}
|
|
106
107
|
return;
|
|
107
108
|
}
|
|
108
|
-
if (selection ===
|
|
109
|
+
if (selection === "__ask__") {
|
|
109
110
|
await askOracleFlow(version, userConfig);
|
|
110
111
|
continue;
|
|
111
112
|
}
|
|
112
|
-
if (selection ===
|
|
113
|
+
if (selection === "__older__") {
|
|
113
114
|
showingOlder = true;
|
|
114
115
|
continue;
|
|
115
116
|
}
|
|
116
|
-
if (selection ===
|
|
117
|
+
if (selection === "__reset__") {
|
|
117
118
|
showingOlder = false;
|
|
118
119
|
continue;
|
|
119
120
|
}
|
|
@@ -123,13 +124,20 @@ export async function launchTui({ version, printIntro = true }) {
|
|
|
123
124
|
async function fetchSessionBuckets() {
|
|
124
125
|
const all = await sessionStore.listSessions();
|
|
125
126
|
const cutoff = Date.now() - RECENT_WINDOW_HOURS * 60 * 60 * 1000;
|
|
126
|
-
const recent = all
|
|
127
|
+
const recent = all
|
|
128
|
+
.filter((meta) => new Date(meta.createdAt).getTime() >= cutoff)
|
|
129
|
+
.slice(0, PAGE_SIZE);
|
|
127
130
|
const olderAll = all.filter((meta) => new Date(meta.createdAt).getTime() < cutoff);
|
|
128
131
|
const older = olderAll.slice(0, PAGE_SIZE);
|
|
129
132
|
const hasMoreOlder = olderAll.length > PAGE_SIZE;
|
|
130
133
|
if (recent.length === 0 && older.length === 0 && olderAll.length > 0) {
|
|
131
134
|
// No recent entries; fall back to top 10 overall.
|
|
132
|
-
return {
|
|
135
|
+
return {
|
|
136
|
+
recent: olderAll.slice(0, PAGE_SIZE),
|
|
137
|
+
older: [],
|
|
138
|
+
hasMoreOlder: olderAll.length > PAGE_SIZE,
|
|
139
|
+
olderTotal: olderAll.length,
|
|
140
|
+
};
|
|
133
141
|
}
|
|
134
142
|
return { recent, older, hasMoreOlder, olderTotal: olderAll.length };
|
|
135
143
|
}
|
|
@@ -153,78 +161,80 @@ async function showSessionDetail(sessionId) {
|
|
|
153
161
|
}
|
|
154
162
|
const prompt = await readStoredPrompt(sessionId);
|
|
155
163
|
if (prompt) {
|
|
156
|
-
console.log(chalk.bold(
|
|
164
|
+
console.log(chalk.bold("Prompt:"));
|
|
157
165
|
console.log(renderMarkdownAnsi(prompt));
|
|
158
|
-
console.log(dim(
|
|
166
|
+
console.log(dim("---"));
|
|
159
167
|
}
|
|
160
168
|
const logPath = await getSessionLogPath(sessionId);
|
|
161
169
|
if (logPath) {
|
|
162
170
|
console.log(dim(`Log file: ${logPath}`));
|
|
163
171
|
}
|
|
164
|
-
console.log(
|
|
172
|
+
console.log("");
|
|
165
173
|
await renderSessionLog(sessionId);
|
|
166
|
-
const isRunning = meta.status ===
|
|
174
|
+
const isRunning = meta.status === "running";
|
|
167
175
|
const modelActions = meta.models?.map((run) => ({
|
|
168
176
|
name: `View ${run.model} log (${run.status})`,
|
|
169
177
|
value: `log:${run.model}`,
|
|
170
178
|
})) ?? [];
|
|
171
179
|
const actions = [
|
|
172
|
-
{ name:
|
|
180
|
+
{ name: "View combined log", value: "log:__all__" },
|
|
173
181
|
...modelActions,
|
|
174
|
-
...(isRunning ? [{ name:
|
|
175
|
-
{ name:
|
|
182
|
+
...(isRunning ? [{ name: "Refresh", value: "refresh" }] : []),
|
|
183
|
+
{ name: "Back", value: "back" },
|
|
176
184
|
];
|
|
177
185
|
let next;
|
|
178
186
|
try {
|
|
179
187
|
({ next } = await inquirer.prompt([
|
|
180
188
|
{
|
|
181
|
-
name:
|
|
182
|
-
type:
|
|
183
|
-
message:
|
|
189
|
+
name: "next",
|
|
190
|
+
type: "select",
|
|
191
|
+
message: "Actions",
|
|
184
192
|
choices: actions,
|
|
185
193
|
},
|
|
186
194
|
]));
|
|
187
195
|
}
|
|
188
196
|
catch (error) {
|
|
189
197
|
const message = error instanceof Error ? error.message : String(error);
|
|
190
|
-
if (message.includes(
|
|
191
|
-
console.log(chalk.green(
|
|
198
|
+
if (message.includes("SIGINT") || message.includes("force closed the prompt")) {
|
|
199
|
+
console.log(chalk.green("🧿 Closing the book. See you next prompt."));
|
|
192
200
|
return;
|
|
193
201
|
}
|
|
194
|
-
console.error(chalk.red(
|
|
202
|
+
console.error(chalk.red("Paging failed; returning to session list."), message);
|
|
195
203
|
return;
|
|
196
204
|
}
|
|
197
|
-
if (next ===
|
|
205
|
+
if (next === "back") {
|
|
198
206
|
return;
|
|
199
207
|
}
|
|
200
|
-
if (next ===
|
|
208
|
+
if (next === "refresh") {
|
|
201
209
|
continue;
|
|
202
210
|
}
|
|
203
|
-
if (next.startsWith(
|
|
204
|
-
const [, target] = next.split(
|
|
205
|
-
await renderSessionLog(sessionId, target ===
|
|
211
|
+
if (next.startsWith("log:")) {
|
|
212
|
+
const [, target] = next.split(":");
|
|
213
|
+
await renderSessionLog(sessionId, target === "__all__" ? undefined : target);
|
|
206
214
|
}
|
|
207
215
|
}
|
|
208
216
|
}
|
|
209
217
|
async function renderSessionLog(sessionId, model) {
|
|
210
|
-
const raw = model
|
|
211
|
-
|
|
218
|
+
const raw = model
|
|
219
|
+
? await sessionStore.readModelLog(sessionId, model)
|
|
220
|
+
: await sessionStore.readLog(sessionId);
|
|
221
|
+
const headerLabel = model ? `Log (${model})` : "Log";
|
|
212
222
|
console.log(chalk.bold(headerLabel));
|
|
213
223
|
const text = trimBeforeFirstAnswer(raw);
|
|
214
|
-
const size = Buffer.byteLength(text,
|
|
224
|
+
const size = Buffer.byteLength(text, "utf8");
|
|
215
225
|
if (size > MAX_RENDER_BYTES) {
|
|
216
226
|
console.log(chalk.yellow(`Log is large (${size.toLocaleString()} bytes). Rendering raw text; open the log file for full context.`));
|
|
217
227
|
process.stdout.write(text);
|
|
218
|
-
console.log(
|
|
228
|
+
console.log("");
|
|
219
229
|
return;
|
|
220
230
|
}
|
|
221
231
|
if (!text.trim()) {
|
|
222
|
-
console.log(dim(
|
|
223
|
-
console.log(
|
|
232
|
+
console.log(dim("(log is empty)"));
|
|
233
|
+
console.log("");
|
|
224
234
|
return;
|
|
225
235
|
}
|
|
226
236
|
process.stdout.write(renderMarkdownAnsi(text));
|
|
227
|
-
console.log(
|
|
237
|
+
console.log("");
|
|
228
238
|
}
|
|
229
239
|
async function getSessionLogPath(sessionId) {
|
|
230
240
|
try {
|
|
@@ -237,14 +247,14 @@ async function getSessionLogPath(sessionId) {
|
|
|
237
247
|
}
|
|
238
248
|
function printSessionHeader(meta) {
|
|
239
249
|
console.log(chalk.bold(`Session ${chalk.cyan(meta.id)}`));
|
|
240
|
-
console.log(`${chalk.white(
|
|
241
|
-
console.log(`${chalk.white(
|
|
250
|
+
console.log(`${chalk.white("Status:")} ${meta.status}`);
|
|
251
|
+
console.log(`${chalk.white("Created:")} ${meta.createdAt}`);
|
|
242
252
|
if (meta.model) {
|
|
243
|
-
console.log(`${chalk.white(
|
|
253
|
+
console.log(`${chalk.white("Model:")} ${meta.model}`);
|
|
244
254
|
}
|
|
245
255
|
const mode = meta.mode ?? meta.options?.mode;
|
|
246
256
|
if (mode) {
|
|
247
|
-
console.log(`${chalk.white(
|
|
257
|
+
console.log(`${chalk.white("Mode:")} ${mode}`);
|
|
248
258
|
}
|
|
249
259
|
if (meta.errorMessage) {
|
|
250
260
|
console.log(chalk.red(`Error: ${meta.errorMessage}`));
|
|
@@ -254,66 +264,66 @@ function printModelSummaries(models) {
|
|
|
254
264
|
if (models.length === 0) {
|
|
255
265
|
return;
|
|
256
266
|
}
|
|
257
|
-
console.log(chalk.bold(
|
|
267
|
+
console.log(chalk.bold("Models:"));
|
|
258
268
|
for (const run of models) {
|
|
259
269
|
const usage = run.usage
|
|
260
270
|
? ` tok=${formatTokenCount(run.usage.outputTokens ?? 0)}/${formatTokenCount(run.usage.totalTokens ?? 0)}`
|
|
261
|
-
:
|
|
271
|
+
: "";
|
|
262
272
|
console.log(` - ${chalk.cyan(run.model)} — ${run.status}${usage}`);
|
|
263
273
|
}
|
|
264
|
-
console.log(
|
|
274
|
+
console.log("");
|
|
265
275
|
}
|
|
266
276
|
async function askOracleFlow(version, userConfig) {
|
|
267
277
|
const modelChoices = Object.keys(MODEL_CONFIGS);
|
|
268
278
|
const hasApiKey = Boolean(process.env.OPENAI_API_KEY);
|
|
269
|
-
const initialMode = hasApiKey ?
|
|
279
|
+
const initialMode = hasApiKey ? "api" : "browser";
|
|
270
280
|
const preferredMode = userConfig.engine ?? initialMode;
|
|
271
281
|
const wizardQuestions = [
|
|
272
282
|
{
|
|
273
|
-
name:
|
|
274
|
-
type:
|
|
275
|
-
message:
|
|
283
|
+
name: "promptInput",
|
|
284
|
+
type: "input",
|
|
285
|
+
message: "Paste your prompt text or a path to a file (leave blank to cancel):",
|
|
276
286
|
},
|
|
277
287
|
...(hasApiKey
|
|
278
288
|
? [
|
|
279
289
|
{
|
|
280
|
-
name:
|
|
281
|
-
type:
|
|
282
|
-
message:
|
|
290
|
+
name: "mode",
|
|
291
|
+
type: "select",
|
|
292
|
+
message: "Engine",
|
|
283
293
|
default: preferredMode,
|
|
284
294
|
choices: [
|
|
285
|
-
{ name:
|
|
286
|
-
{ name:
|
|
295
|
+
{ name: "API", value: "api" },
|
|
296
|
+
{ name: "Browser", value: "browser" },
|
|
287
297
|
],
|
|
288
298
|
},
|
|
289
299
|
]
|
|
290
300
|
: [
|
|
291
301
|
{
|
|
292
|
-
name:
|
|
293
|
-
type:
|
|
294
|
-
message:
|
|
302
|
+
name: "mode",
|
|
303
|
+
type: "select",
|
|
304
|
+
message: "Engine",
|
|
295
305
|
default: preferredMode,
|
|
296
|
-
choices: [{ name:
|
|
306
|
+
choices: [{ name: "Browser", value: "browser" }],
|
|
297
307
|
},
|
|
298
308
|
]),
|
|
299
309
|
{
|
|
300
|
-
name:
|
|
301
|
-
type:
|
|
302
|
-
message:
|
|
310
|
+
name: "slug",
|
|
311
|
+
type: "input",
|
|
312
|
+
message: "Optional slug (3–5 words, leave blank for auto):",
|
|
303
313
|
},
|
|
304
314
|
{
|
|
305
|
-
name:
|
|
306
|
-
type:
|
|
307
|
-
message:
|
|
315
|
+
name: "model",
|
|
316
|
+
type: "select",
|
|
317
|
+
message: "Model",
|
|
308
318
|
default: DEFAULT_MODEL,
|
|
309
319
|
choices: modelChoices,
|
|
310
320
|
},
|
|
311
321
|
{
|
|
312
|
-
name:
|
|
313
|
-
type:
|
|
314
|
-
message:
|
|
322
|
+
name: "models",
|
|
323
|
+
type: "checkbox",
|
|
324
|
+
message: "Additional API models to fan out to (optional)",
|
|
315
325
|
choices: modelChoices,
|
|
316
|
-
when: (ans) => ans.mode ===
|
|
326
|
+
when: (ans) => ans.mode === "api",
|
|
317
327
|
filter: (values) => Array.isArray(values)
|
|
318
328
|
? values
|
|
319
329
|
.map((entry) => entry.trim())
|
|
@@ -321,50 +331,52 @@ async function askOracleFlow(version, userConfig) {
|
|
|
321
331
|
: [],
|
|
322
332
|
},
|
|
323
333
|
{
|
|
324
|
-
name:
|
|
325
|
-
type:
|
|
326
|
-
message:
|
|
334
|
+
name: "files",
|
|
335
|
+
type: "input",
|
|
336
|
+
message: "Files or globs to attach (comma-separated, optional):",
|
|
327
337
|
filter: (value) => value
|
|
328
|
-
.split(
|
|
338
|
+
.split(",")
|
|
329
339
|
.map((entry) => entry.trim())
|
|
330
340
|
.filter(Boolean),
|
|
331
341
|
},
|
|
332
342
|
{
|
|
333
|
-
name:
|
|
334
|
-
type:
|
|
335
|
-
message:
|
|
336
|
-
default:
|
|
337
|
-
when: (ans) => ans.mode ===
|
|
343
|
+
name: "chromeProfile",
|
|
344
|
+
type: "input",
|
|
345
|
+
message: "Chrome profile to reuse cookies from:",
|
|
346
|
+
default: "Default",
|
|
347
|
+
when: (ans) => ans.mode === "browser",
|
|
338
348
|
},
|
|
339
349
|
{
|
|
340
|
-
name:
|
|
341
|
-
type:
|
|
342
|
-
message:
|
|
343
|
-
when: (ans) => ans.mode ===
|
|
350
|
+
name: "chromeCookiePath",
|
|
351
|
+
type: "input",
|
|
352
|
+
message: "Cookie DB path (Chromium/Edge, optional):",
|
|
353
|
+
when: (ans) => ans.mode === "browser",
|
|
344
354
|
},
|
|
345
355
|
{
|
|
346
|
-
name:
|
|
347
|
-
type:
|
|
348
|
-
message:
|
|
356
|
+
name: "hideWindow",
|
|
357
|
+
type: "confirm",
|
|
358
|
+
message: "Hide Chrome window (macOS headful only)?",
|
|
349
359
|
default: false,
|
|
350
|
-
when: (ans) => ans.mode ===
|
|
360
|
+
when: (ans) => ans.mode === "browser",
|
|
351
361
|
},
|
|
352
362
|
{
|
|
353
|
-
name:
|
|
354
|
-
type:
|
|
355
|
-
message:
|
|
363
|
+
name: "keepBrowser",
|
|
364
|
+
type: "confirm",
|
|
365
|
+
message: "Keep browser open after completion?",
|
|
356
366
|
default: false,
|
|
357
|
-
when: (ans) => ans.mode ===
|
|
367
|
+
when: (ans) => ans.mode === "browser",
|
|
358
368
|
},
|
|
359
369
|
];
|
|
360
370
|
const answers = await inquirer.prompt(wizardQuestions);
|
|
361
371
|
const mode = (answers.mode ?? initialMode);
|
|
362
372
|
const prompt = await resolvePromptInput(answers.promptInput);
|
|
363
373
|
if (!prompt.trim()) {
|
|
364
|
-
console.log(chalk.yellow(
|
|
374
|
+
console.log(chalk.yellow("Cancelled."));
|
|
365
375
|
return;
|
|
366
376
|
}
|
|
367
|
-
const promptWithSuffix = userConfig.promptSuffix
|
|
377
|
+
const promptWithSuffix = userConfig.promptSuffix
|
|
378
|
+
? `${prompt.trim()}\n${userConfig.promptSuffix}`
|
|
379
|
+
: prompt;
|
|
368
380
|
await sessionStore.ensureStorage();
|
|
369
381
|
await pruneOldSessions(userConfig.sessionRetentionHours, (message) => console.log(chalk.dim(message)));
|
|
370
382
|
const normalizedMultiModels = Array.isArray(answers.models) && answers.models.length > 0
|
|
@@ -374,6 +386,7 @@ async function askOracleFlow(version, userConfig) {
|
|
|
374
386
|
prompt: promptWithSuffix,
|
|
375
387
|
model: answers.model,
|
|
376
388
|
file: answers.files,
|
|
389
|
+
maxFileSizeBytes: resolveConfiguredMaxFileSizeBytes(userConfig, process.env),
|
|
377
390
|
models: normalizedMultiModels.length > 1 ? normalizedMultiModels : undefined,
|
|
378
391
|
slug: answers.slug,
|
|
379
392
|
filesReport: false,
|
|
@@ -388,12 +401,12 @@ async function askOracleFlow(version, userConfig) {
|
|
|
388
401
|
sessionId: undefined,
|
|
389
402
|
verbose: false,
|
|
390
403
|
heartbeatIntervalMs: undefined,
|
|
391
|
-
browserAttachments:
|
|
404
|
+
browserAttachments: "auto",
|
|
392
405
|
browserInlineFiles: false,
|
|
393
406
|
browserBundleFiles: false,
|
|
394
407
|
background: undefined,
|
|
395
408
|
};
|
|
396
|
-
const browserConfig = mode ===
|
|
409
|
+
const browserConfig = mode === "browser"
|
|
397
410
|
? await buildBrowserConfig({
|
|
398
411
|
browserChromeProfile: answers.chromeProfile,
|
|
399
412
|
browserCookiePath: answers.chromeCookiePath,
|
|
@@ -428,7 +441,7 @@ async function askOracleFlow(version, userConfig) {
|
|
|
428
441
|
return true;
|
|
429
442
|
};
|
|
430
443
|
console.log(chalk.bold(`Session ${sessionMeta.id} starting...`));
|
|
431
|
-
console.log(dim(`Log path: ${path.join(os.homedir(),
|
|
444
|
+
console.log(dim(`Log path: ${path.join(os.homedir(), ".oracle", "sessions", sessionMeta.id, "output.log")}`));
|
|
432
445
|
try {
|
|
433
446
|
await performSessionRun({
|
|
434
447
|
sessionMeta,
|
|
@@ -461,7 +474,7 @@ async function resolvePromptInput(rawInput) {
|
|
|
461
474
|
try {
|
|
462
475
|
const stats = await fs.stat(asPath);
|
|
463
476
|
if (stats.isFile()) {
|
|
464
|
-
const contents = await fs.readFile(asPath,
|
|
477
|
+
const contents = await fs.readFile(asPath, "utf8");
|
|
465
478
|
return contents;
|
|
466
479
|
}
|
|
467
480
|
}
|
|
@@ -483,4 +496,4 @@ async function readStoredPrompt(sessionId) {
|
|
|
483
496
|
}
|
|
484
497
|
// Exported for testing
|
|
485
498
|
export { askOracleFlow, showSessionDetail };
|
|
486
|
-
export { resolveSessionCost as resolveCost } from
|
|
499
|
+
export { resolveSessionCost as resolveCost } from "../sessionTable.js";
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import os from
|
|
2
|
-
import path from
|
|
3
|
-
import { sessionStore } from
|
|
1
|
+
import os from "node:os";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { sessionStore } from "../sessionStore.js";
|
|
4
4
|
export function resolveOutputPath(input, cwd) {
|
|
5
5
|
if (!input || input.trim().length === 0) {
|
|
6
6
|
return undefined;
|
|
7
7
|
}
|
|
8
|
-
const expanded = input.startsWith(
|
|
9
|
-
if (expanded ===
|
|
8
|
+
const expanded = input.startsWith("~/") ? path.join(os.homedir(), input.slice(2)) : input;
|
|
9
|
+
if (expanded === "-" || expanded === "/dev/stdout") {
|
|
10
10
|
return expanded;
|
|
11
11
|
}
|
|
12
12
|
const absolute = path.isAbsolute(expanded) ? expanded : path.resolve(cwd, expanded);
|
package/dist/src/config.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import fs from
|
|
2
|
-
import path from
|
|
3
|
-
import JSON5 from
|
|
4
|
-
import { getOracleHomeDir } from
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import JSON5 from "json5";
|
|
4
|
+
import { getOracleHomeDir } from "./oracleHome.js";
|
|
5
5
|
function resolveConfigPath() {
|
|
6
|
-
return path.join(getOracleHomeDir(),
|
|
6
|
+
return path.join(getOracleHomeDir(), "config.json");
|
|
7
7
|
}
|
|
8
8
|
export async function loadUserConfig() {
|
|
9
9
|
const CONFIG_PATH = resolveConfigPath();
|
|
10
10
|
try {
|
|
11
|
-
const raw = await fs.readFile(CONFIG_PATH,
|
|
11
|
+
const raw = await fs.readFile(CONFIG_PATH, "utf8");
|
|
12
12
|
const parsed = JSON5.parse(raw);
|
|
13
13
|
return { config: parsed ?? {}, path: CONFIG_PATH, loaded: true };
|
|
14
14
|
}
|
|
15
15
|
catch (error) {
|
|
16
16
|
const code = error.code;
|
|
17
|
-
if (code ===
|
|
17
|
+
if (code === "ENOENT") {
|
|
18
18
|
return { config: {}, path: CONFIG_PATH, loaded: false };
|
|
19
19
|
}
|
|
20
20
|
console.warn(`Failed to read ${CONFIG_PATH}: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import { mkdir } from "node:fs/promises";
|
|
4
|
+
import { launchChrome, connectWithNewTab, closeTab } from "../browser/chromeLifecycle.js";
|
|
5
|
+
import { resolveBrowserConfig } from "../browser/config.js";
|
|
6
|
+
import { readDevToolsPort, writeDevToolsActivePort, writeChromePid, cleanupStaleProfileState, verifyDevToolsReachable, } from "../browser/profileState.js";
|
|
7
|
+
export async function openGeminiBrowserSession(input) {
|
|
8
|
+
const { browserConfig, keepBrowserDefault, purpose, log } = input;
|
|
9
|
+
const resolvedConfig = resolveBrowserConfig({
|
|
10
|
+
...browserConfig,
|
|
11
|
+
manualLogin: true,
|
|
12
|
+
keepBrowser: browserConfig?.keepBrowser ?? keepBrowserDefault,
|
|
13
|
+
});
|
|
14
|
+
const profileDir = resolvedConfig.manualLoginProfileDir ?? path.join(os.homedir(), ".oracle", "browser-profile");
|
|
15
|
+
await mkdir(profileDir, { recursive: true });
|
|
16
|
+
const keepBrowser = Boolean(resolvedConfig.keepBrowser);
|
|
17
|
+
let port = await readDevToolsPort(profileDir);
|
|
18
|
+
let launchedChrome = null;
|
|
19
|
+
let chromeWasLaunched = false;
|
|
20
|
+
if (port) {
|
|
21
|
+
const probe = await verifyDevToolsReachable({ port });
|
|
22
|
+
if (!probe.ok) {
|
|
23
|
+
log?.(`[gemini-web] Stale DevTools port ${port}; launching fresh Chrome for ${purpose}.`);
|
|
24
|
+
await cleanupStaleProfileState(profileDir, log, { lockRemovalMode: "if_oracle_pid_dead" });
|
|
25
|
+
port = null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (!port) {
|
|
29
|
+
log?.(`[gemini-web] Launching Chrome for ${purpose}.`);
|
|
30
|
+
launchedChrome = await launchChrome(resolvedConfig, profileDir, log ?? (() => { }));
|
|
31
|
+
port = launchedChrome.port;
|
|
32
|
+
chromeWasLaunched = true;
|
|
33
|
+
await writeDevToolsActivePort(profileDir, port);
|
|
34
|
+
if (launchedChrome.pid) {
|
|
35
|
+
await writeChromePid(profileDir, launchedChrome.pid);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
log?.(`[gemini-web] Reusing Chrome on port ${port} for ${purpose}.`);
|
|
40
|
+
}
|
|
41
|
+
const connection = await connectWithNewTab(port, log ?? (() => { }), undefined);
|
|
42
|
+
const client = connection.client;
|
|
43
|
+
const targetId = connection.targetId;
|
|
44
|
+
const close = async () => {
|
|
45
|
+
if (keepBrowser) {
|
|
46
|
+
try {
|
|
47
|
+
await client.close();
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
/* ignore */
|
|
51
|
+
}
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (targetId && port) {
|
|
55
|
+
await closeTab(port, targetId, log ?? (() => { })).catch(() => undefined);
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
await client.close();
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
/* ignore */
|
|
62
|
+
}
|
|
63
|
+
if (chromeWasLaunched && launchedChrome) {
|
|
64
|
+
try {
|
|
65
|
+
launchedChrome.kill();
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
/* ignore */
|
|
69
|
+
}
|
|
70
|
+
await cleanupStaleProfileState(profileDir, log, { lockRemovalMode: "never" }).catch(() => undefined);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
return {
|
|
74
|
+
profileDir,
|
|
75
|
+
port,
|
|
76
|
+
client,
|
|
77
|
+
targetId: targetId ?? undefined,
|
|
78
|
+
close,
|
|
79
|
+
};
|
|
80
|
+
}
|