@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,10 +1,10 @@
|
|
|
1
|
-
import { z } from
|
|
2
|
-
import { getCliVersion } from
|
|
3
|
-
import { LoggingMessageNotificationParamsSchema } from
|
|
4
|
-
import { ensureBrowserAvailable, mapConsultToRunOptions } from
|
|
5
|
-
import { sessionStore } from
|
|
6
|
-
import { resolveRemoteServiceConfig } from
|
|
7
|
-
import { createRemoteBrowserExecutor } from
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getCliVersion } from "../../version.js";
|
|
3
|
+
import { LoggingMessageNotificationParamsSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
4
|
+
import { ensureBrowserAvailable, mapConsultToRunOptions } from "../utils.js";
|
|
5
|
+
import { sessionStore } from "../../sessionStore.js";
|
|
6
|
+
import { resolveRemoteServiceConfig } from "../../remote/remoteServiceConfig.js";
|
|
7
|
+
import { createRemoteBrowserExecutor } from "../../remote/client.js";
|
|
8
8
|
async function readSessionLogTail(sessionId, maxBytes) {
|
|
9
9
|
try {
|
|
10
10
|
const log = await sessionStore.readLog(sessionId);
|
|
@@ -17,62 +17,59 @@ async function readSessionLogTail(sessionId, maxBytes) {
|
|
|
17
17
|
return null;
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
-
import { performSessionRun } from
|
|
21
|
-
import { CHATGPT_URL } from
|
|
22
|
-
import { consultInputSchema } from
|
|
23
|
-
import { loadUserConfig } from
|
|
24
|
-
import { resolveNotificationSettings } from
|
|
25
|
-
import { mapModelToBrowserLabel, resolveBrowserModelLabel } from
|
|
20
|
+
import { performSessionRun } from "../../cli/sessionRunner.js";
|
|
21
|
+
import { CHATGPT_URL } from "../../browser/constants.js";
|
|
22
|
+
import { consultInputSchema } from "../types.js";
|
|
23
|
+
import { loadUserConfig } from "../../config.js";
|
|
24
|
+
import { resolveNotificationSettings } from "../../cli/notifier.js";
|
|
25
|
+
import { mapModelToBrowserLabel, resolveBrowserModelLabel } from "../../cli/browserConfig.js";
|
|
26
26
|
// Use raw shapes so the MCP SDK (with its bundled Zod) wraps them and emits valid JSON Schema.
|
|
27
27
|
const consultInputShape = {
|
|
28
|
-
prompt: z
|
|
29
|
-
.string()
|
|
30
|
-
.min(1, 'Prompt is required.')
|
|
31
|
-
.describe('User prompt to run.'),
|
|
28
|
+
prompt: z.string().min(1, "Prompt is required.").describe("User prompt to run."),
|
|
32
29
|
files: z
|
|
33
30
|
.array(z.string())
|
|
34
31
|
.default([])
|
|
35
|
-
.describe(
|
|
32
|
+
.describe("Optional file paths or glob patterns (like the CLI `--file`). Resolved relative to the MCP server working directory."),
|
|
36
33
|
model: z
|
|
37
34
|
.string()
|
|
38
35
|
.optional()
|
|
39
|
-
.describe(
|
|
36
|
+
.describe("Single model name/label. Prefer setting `engine` explicitly to avoid default surprises."),
|
|
40
37
|
models: z
|
|
41
38
|
.array(z.string())
|
|
42
39
|
.optional()
|
|
43
|
-
.describe(
|
|
40
|
+
.describe("Multi-model fan-out (API engine only). Cannot be combined with browser automation."),
|
|
44
41
|
engine: z
|
|
45
|
-
.enum([
|
|
42
|
+
.enum(["api", "browser"])
|
|
46
43
|
.optional()
|
|
47
|
-
.describe(
|
|
44
|
+
.describe("Execution engine. `api` uses OpenAI/other providers. `browser` automates the ChatGPT web UI (supports attachments and ChatGPT-only model labels)."),
|
|
48
45
|
browserModelLabel: z
|
|
49
46
|
.string()
|
|
50
47
|
.optional()
|
|
51
48
|
.describe('Browser-only: explicit ChatGPT UI label to select (overrides model mapping). Example: "GPT-5.2 Thinking".'),
|
|
52
49
|
browserAttachments: z
|
|
53
|
-
.enum([
|
|
50
|
+
.enum(["auto", "never", "always"])
|
|
54
51
|
.optional()
|
|
55
52
|
.describe('Browser-only: how to deliver `files`. Use "always" for real ChatGPT file uploads (including images/PDFs). Use "never" to paste file contents inline. "auto" chooses based on prompt size.'),
|
|
56
53
|
browserBundleFiles: z
|
|
57
54
|
.boolean()
|
|
58
55
|
.optional()
|
|
59
|
-
.describe(
|
|
56
|
+
.describe("Browser-only: bundle many files into a single upload (helps with upload limits)."),
|
|
60
57
|
browserThinkingTime: z
|
|
61
|
-
.enum([
|
|
58
|
+
.enum(["light", "standard", "extended", "heavy"])
|
|
62
59
|
.optional()
|
|
63
|
-
.describe(
|
|
60
|
+
.describe("Browser-only: set ChatGPT thinking time when supported by the chosen model."),
|
|
64
61
|
browserKeepBrowser: z
|
|
65
62
|
.boolean()
|
|
66
63
|
.optional()
|
|
67
|
-
.describe(
|
|
64
|
+
.describe("Browser-only: keep Chrome running after completion (useful for debugging)."),
|
|
68
65
|
search: z
|
|
69
66
|
.boolean()
|
|
70
67
|
.optional()
|
|
71
|
-
.describe(
|
|
68
|
+
.describe("API-only: enable/disable the provider search tool (browser engine ignores this)."),
|
|
72
69
|
slug: z
|
|
73
70
|
.string()
|
|
74
71
|
.optional()
|
|
75
|
-
.describe(
|
|
72
|
+
.describe("Optional human-friendly session id (used for later `oracle sessions` lookups)."),
|
|
76
73
|
};
|
|
77
74
|
const consultModelSummaryShape = z.object({
|
|
78
75
|
model: z.string(),
|
|
@@ -129,7 +126,7 @@ export function summarizeModelRunsForConsult(runs) {
|
|
|
129
126
|
: undefined;
|
|
130
127
|
return {
|
|
131
128
|
model: run.model,
|
|
132
|
-
status: run.status ??
|
|
129
|
+
status: run.status ?? "unknown",
|
|
133
130
|
startedAt: run.startedAt,
|
|
134
131
|
completedAt: run.completedAt,
|
|
135
132
|
usage: run.usage,
|
|
@@ -139,15 +136,42 @@ export function summarizeModelRunsForConsult(runs) {
|
|
|
139
136
|
};
|
|
140
137
|
});
|
|
141
138
|
}
|
|
139
|
+
export function buildConsultBrowserConfig({ userConfig, env, runModel, inputModel, browserModelLabel, browserThinkingTime, browserKeepBrowser, }) {
|
|
140
|
+
const configuredBrowser = userConfig.browser ?? {};
|
|
141
|
+
const envProfileDir = (env.ORACLE_BROWSER_PROFILE_DIR ?? "").trim();
|
|
142
|
+
const hasProfileDir = envProfileDir.length > 0;
|
|
143
|
+
const preferredLabel = (browserModelLabel ?? inputModel)?.trim();
|
|
144
|
+
const isChatGptModel = runModel.startsWith("gpt-") && !runModel.includes("codex");
|
|
145
|
+
const desiredModelLabel = isChatGptModel
|
|
146
|
+
? mapModelToBrowserLabel(runModel)
|
|
147
|
+
: resolveBrowserModelLabel(preferredLabel, runModel);
|
|
148
|
+
const configuredUrl = configuredBrowser.chatgptUrl ?? configuredBrowser.url ?? CHATGPT_URL;
|
|
149
|
+
const manualLogin = hasProfileDir ? true : (configuredBrowser.manualLogin ?? false);
|
|
150
|
+
return {
|
|
151
|
+
...configuredBrowser,
|
|
152
|
+
url: configuredUrl,
|
|
153
|
+
chatgptUrl: configuredUrl,
|
|
154
|
+
cookieSync: !manualLogin,
|
|
155
|
+
headless: configuredBrowser.headless ?? false,
|
|
156
|
+
hideWindow: configuredBrowser.hideWindow ?? false,
|
|
157
|
+
keepBrowser: browserKeepBrowser ?? configuredBrowser.keepBrowser ?? false,
|
|
158
|
+
manualLogin,
|
|
159
|
+
manualLoginProfileDir: manualLogin
|
|
160
|
+
? ((envProfileDir || configuredBrowser.manualLoginProfileDir) ?? null)
|
|
161
|
+
: null,
|
|
162
|
+
thinkingTime: browserThinkingTime ?? configuredBrowser.thinkingTime,
|
|
163
|
+
desiredModel: desiredModelLabel || mapModelToBrowserLabel(runModel),
|
|
164
|
+
};
|
|
165
|
+
}
|
|
142
166
|
export function registerConsultTool(server) {
|
|
143
|
-
server.registerTool(
|
|
144
|
-
title:
|
|
167
|
+
server.registerTool("consult", {
|
|
168
|
+
title: "Run an oracle session",
|
|
145
169
|
description: 'Run a one-shot Oracle session (API or ChatGPT browser automation). Use `files` to attach project context. For browser-based image/file uploads, set `browserAttachments:"always"`. Sessions are stored under `ORACLE_HOME_DIR` (shared with the CLI).',
|
|
146
170
|
// Cast to any to satisfy SDK typings across differing Zod versions.
|
|
147
171
|
inputSchema: consultInputShape,
|
|
148
172
|
outputSchema: consultOutputShape,
|
|
149
173
|
}, async (input) => {
|
|
150
|
-
const textContent = (text) => [{ type:
|
|
174
|
+
const textContent = (text) => [{ type: "text", text }];
|
|
151
175
|
const { prompt, files, model, models, engine, search, browserModelLabel, browserAttachments, browserBundleFiles, browserThinkingTime, browserKeepBrowser, slug, } = consultInputSchema.parse(input);
|
|
152
176
|
const { config: userConfig } = await loadUserConfig();
|
|
153
177
|
const { runOptions, resolvedEngine } = mapConsultToRunOptions({
|
|
@@ -164,15 +188,17 @@ export function registerConsultTool(server) {
|
|
|
164
188
|
});
|
|
165
189
|
const cwd = process.cwd();
|
|
166
190
|
const resolvedRemote = resolveRemoteServiceConfig({ userConfig, env: process.env });
|
|
167
|
-
const browserGuard = ensureBrowserAvailable(resolvedEngine, {
|
|
168
|
-
|
|
191
|
+
const browserGuard = ensureBrowserAvailable(resolvedEngine, {
|
|
192
|
+
remoteHost: resolvedRemote.host,
|
|
193
|
+
});
|
|
194
|
+
if (resolvedEngine === "browser" && browserGuard) {
|
|
169
195
|
return {
|
|
170
196
|
isError: true,
|
|
171
197
|
content: textContent(browserGuard),
|
|
172
198
|
};
|
|
173
199
|
}
|
|
174
200
|
let browserDeps;
|
|
175
|
-
if (resolvedEngine ===
|
|
201
|
+
if (resolvedEngine === "browser" && resolvedRemote.host) {
|
|
176
202
|
if (!resolvedRemote.token) {
|
|
177
203
|
return {
|
|
178
204
|
isError: true,
|
|
@@ -180,32 +206,23 @@ export function registerConsultTool(server) {
|
|
|
180
206
|
};
|
|
181
207
|
}
|
|
182
208
|
browserDeps = {
|
|
183
|
-
executeBrowser: createRemoteBrowserExecutor({
|
|
209
|
+
executeBrowser: createRemoteBrowserExecutor({
|
|
210
|
+
host: resolvedRemote.host,
|
|
211
|
+
token: resolvedRemote.token,
|
|
212
|
+
}),
|
|
184
213
|
};
|
|
185
214
|
}
|
|
186
215
|
let browserConfig;
|
|
187
|
-
if (resolvedEngine ===
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
const manualLogin = hasProfileDir;
|
|
198
|
-
browserConfig = {
|
|
199
|
-
url: configuredUrl ?? CHATGPT_URL,
|
|
200
|
-
cookieSync: !manualLogin,
|
|
201
|
-
headless: false,
|
|
202
|
-
hideWindow: false,
|
|
203
|
-
keepBrowser: browserKeepBrowser ?? false,
|
|
204
|
-
manualLogin,
|
|
205
|
-
manualLoginProfileDir: manualLogin ? envProfileDir : null,
|
|
206
|
-
thinkingTime: browserThinkingTime,
|
|
207
|
-
desiredModel: desiredModelLabel || mapModelToBrowserLabel(runOptions.model),
|
|
208
|
-
};
|
|
216
|
+
if (resolvedEngine === "browser") {
|
|
217
|
+
browserConfig = buildConsultBrowserConfig({
|
|
218
|
+
userConfig,
|
|
219
|
+
env: process.env,
|
|
220
|
+
runModel: runOptions.model,
|
|
221
|
+
inputModel: model,
|
|
222
|
+
browserModelLabel,
|
|
223
|
+
browserThinkingTime,
|
|
224
|
+
browserKeepBrowser,
|
|
225
|
+
});
|
|
209
226
|
}
|
|
210
227
|
const notifications = resolveNotificationSettings({
|
|
211
228
|
cliNotify: undefined,
|
|
@@ -222,10 +239,10 @@ export function registerConsultTool(server) {
|
|
|
222
239
|
}, cwd, notifications);
|
|
223
240
|
const logWriter = sessionStore.createLogWriter(sessionMeta.id);
|
|
224
241
|
// Best-effort: emit MCP logging notifications for live chunks but never block the run.
|
|
225
|
-
const sendLog = (text, level =
|
|
242
|
+
const sendLog = (text, level = "info") => server.server
|
|
226
243
|
.sendLoggingMessage(LoggingMessageNotificationParamsSchema.parse({
|
|
227
244
|
level,
|
|
228
|
-
data: { text, bytes: Buffer.byteLength(text,
|
|
245
|
+
data: { text, bytes: Buffer.byteLength(text, "utf8") },
|
|
229
246
|
}))
|
|
230
247
|
.catch(() => { });
|
|
231
248
|
// Stream logs to both the session log and MCP logging notifications, but avoid buffering in memory
|
|
@@ -237,7 +254,7 @@ export function registerConsultTool(server) {
|
|
|
237
254
|
};
|
|
238
255
|
const write = (chunk) => {
|
|
239
256
|
logWriter.writeChunk(chunk);
|
|
240
|
-
sendLog(chunk,
|
|
257
|
+
sendLog(chunk, "debug");
|
|
241
258
|
return true;
|
|
242
259
|
};
|
|
243
260
|
try {
|
|
@@ -271,11 +288,11 @@ export function registerConsultTool(server) {
|
|
|
271
288
|
const logTail = await readSessionLogTail(sessionMeta.id, 4000);
|
|
272
289
|
const modelsSummary = summarizeModelRunsForConsult(finalMeta.models);
|
|
273
290
|
return {
|
|
274
|
-
content: textContent([summary, logTail ||
|
|
291
|
+
content: textContent([summary, logTail || "(log empty)"].join("\n").trim()),
|
|
275
292
|
structuredContent: {
|
|
276
293
|
sessionId: sessionMeta.id,
|
|
277
294
|
status: finalMeta.status,
|
|
278
|
-
output: logTail ??
|
|
295
|
+
output: logTail ?? "",
|
|
279
296
|
models: modelsSummary,
|
|
280
297
|
},
|
|
281
298
|
};
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { ResourceTemplate } from
|
|
2
|
-
import fs from
|
|
3
|
-
import { sessionStore } from
|
|
1
|
+
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import { sessionStore } from "../../sessionStore.js";
|
|
4
4
|
// URIs:
|
|
5
5
|
// - oracle-session://<id>/metadata
|
|
6
6
|
// - oracle-session://<id>/log
|
|
7
7
|
// - oracle-session://<id>/request
|
|
8
8
|
export function registerSessionResources(server) {
|
|
9
|
-
const template = new ResourceTemplate(
|
|
10
|
-
server.registerResource(
|
|
11
|
-
title:
|
|
12
|
-
description:
|
|
9
|
+
const template = new ResourceTemplate("oracle-session://{id}/{kind}", { list: undefined });
|
|
10
|
+
server.registerResource("oracle-session", template, {
|
|
11
|
+
title: "oracle session resources",
|
|
12
|
+
description: "Read stored session metadata, log, or request payload.",
|
|
13
13
|
}, async (uri, variables) => {
|
|
14
14
|
const idRaw = variables?.id;
|
|
15
15
|
const kindRaw = variables?.kind;
|
|
@@ -17,10 +17,10 @@ export function registerSessionResources(server) {
|
|
|
17
17
|
const id = Array.isArray(idRaw) ? idRaw[0] : idRaw;
|
|
18
18
|
const kind = Array.isArray(kindRaw) ? kindRaw[0] : kindRaw;
|
|
19
19
|
if (!id || !kind) {
|
|
20
|
-
throw new Error(
|
|
20
|
+
throw new Error("Missing id or kind");
|
|
21
21
|
}
|
|
22
22
|
switch (kind) {
|
|
23
|
-
case
|
|
23
|
+
case "metadata": {
|
|
24
24
|
const metadata = await sessionStore.readSession(id);
|
|
25
25
|
if (!metadata) {
|
|
26
26
|
throw new Error(`Session "${id}" not found.`);
|
|
@@ -34,7 +34,7 @@ export function registerSessionResources(server) {
|
|
|
34
34
|
],
|
|
35
35
|
};
|
|
36
36
|
}
|
|
37
|
-
case
|
|
37
|
+
case "log": {
|
|
38
38
|
const log = await sessionStore.readLog(id);
|
|
39
39
|
return {
|
|
40
40
|
contents: [
|
|
@@ -45,7 +45,7 @@ export function registerSessionResources(server) {
|
|
|
45
45
|
],
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
|
-
case
|
|
48
|
+
case "request": {
|
|
49
49
|
const request = await sessionStore.readRequest(id);
|
|
50
50
|
if (request) {
|
|
51
51
|
return {
|
|
@@ -58,7 +58,7 @@ export function registerSessionResources(server) {
|
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
60
|
const paths = await sessionStore.getPaths(id);
|
|
61
|
-
const raw = await fs.readFile(paths.request,
|
|
61
|
+
const raw = await fs.readFile(paths.request, "utf8");
|
|
62
62
|
return {
|
|
63
63
|
contents: [
|
|
64
64
|
{
|
|
@@ -1,21 +1,24 @@
|
|
|
1
|
-
import { z } from
|
|
2
|
-
import { sessionStore } from
|
|
3
|
-
import { sessionsInputSchema } from
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { sessionStore } from "../../sessionStore.js";
|
|
3
|
+
import { sessionsInputSchema } from "../types.js";
|
|
4
4
|
const sessionsInputShape = {
|
|
5
5
|
id: z
|
|
6
6
|
.string()
|
|
7
7
|
.optional()
|
|
8
|
-
.describe(
|
|
9
|
-
hours: z
|
|
10
|
-
|
|
8
|
+
.describe("Session id or slug. If set, returns a single session (use detail:true to include metadata/request)."),
|
|
9
|
+
hours: z
|
|
10
|
+
.number()
|
|
11
|
+
.optional()
|
|
12
|
+
.describe("Look back this many hours when listing sessions (default: 24)."),
|
|
13
|
+
limit: z.number().optional().describe("Maximum sessions to return when listing (default: 100)."),
|
|
11
14
|
includeAll: z
|
|
12
15
|
.boolean()
|
|
13
16
|
.optional()
|
|
14
|
-
.describe(
|
|
17
|
+
.describe("Include sessions outside the time window when listing (mirrors `oracle status --all`)."),
|
|
15
18
|
detail: z
|
|
16
19
|
.boolean()
|
|
17
20
|
.optional()
|
|
18
|
-
.describe(
|
|
21
|
+
.describe("When id is set, include session metadata + stored request + full log text."),
|
|
19
22
|
};
|
|
20
23
|
const sessionsOutputShape = {
|
|
21
24
|
entries: z
|
|
@@ -38,14 +41,14 @@ const sessionsOutputShape = {
|
|
|
38
41
|
.optional(),
|
|
39
42
|
};
|
|
40
43
|
export function registerSessionsTool(server) {
|
|
41
|
-
server.registerTool(
|
|
42
|
-
title:
|
|
43
|
-
description:
|
|
44
|
+
server.registerTool("sessions", {
|
|
45
|
+
title: "List or fetch oracle sessions",
|
|
46
|
+
description: "Inspect Oracle session history stored under `ORACLE_HOME_DIR` (shared with the CLI). List recent sessions or fetch one by id/slug (optionally including metadata + request + log).",
|
|
44
47
|
inputSchema: sessionsInputShape,
|
|
45
48
|
outputSchema: sessionsOutputShape,
|
|
46
49
|
}, async (input) => {
|
|
47
|
-
const textContent = (text) => [{ type:
|
|
48
|
-
const { id, hours = 24, limit = 100, includeAll = false, detail = false } = sessionsInputSchema.parse(input);
|
|
50
|
+
const textContent = (text) => [{ type: "text", text }];
|
|
51
|
+
const { id, hours = 24, limit = 100, includeAll = false, detail = false, } = sessionsInputSchema.parse(input);
|
|
49
52
|
if (id) {
|
|
50
53
|
if (!detail) {
|
|
51
54
|
const metadata = await sessionStore.readSession(id);
|
|
@@ -53,7 +56,7 @@ export function registerSessionsTool(server) {
|
|
|
53
56
|
throw new Error(`Session "${id}" not found.`);
|
|
54
57
|
}
|
|
55
58
|
return {
|
|
56
|
-
content: textContent(`${metadata.createdAt} | ${metadata.status} | ${metadata.model ??
|
|
59
|
+
content: textContent(`${metadata.createdAt} | ${metadata.status} | ${metadata.model ?? "n/a"} | ${metadata.id}`),
|
|
57
60
|
structuredContent: {
|
|
58
61
|
entries: [
|
|
59
62
|
{
|
|
@@ -81,12 +84,18 @@ export function registerSessionsTool(server) {
|
|
|
81
84
|
};
|
|
82
85
|
}
|
|
83
86
|
const metas = await sessionStore.listSessions();
|
|
84
|
-
const { entries, truncated, total } = sessionStore.filterSessions(metas, {
|
|
87
|
+
const { entries, truncated, total } = sessionStore.filterSessions(metas, {
|
|
88
|
+
hours,
|
|
89
|
+
includeAll,
|
|
90
|
+
limit,
|
|
91
|
+
});
|
|
85
92
|
return {
|
|
86
93
|
content: [
|
|
87
94
|
{
|
|
88
|
-
type:
|
|
89
|
-
text: entries
|
|
95
|
+
type: "text",
|
|
96
|
+
text: entries
|
|
97
|
+
.map((entry) => `${entry.createdAt} | ${entry.status} | ${entry.model ?? "n/a"} | ${entry.id}`)
|
|
98
|
+
.join("\n"),
|
|
90
99
|
},
|
|
91
100
|
],
|
|
92
101
|
structuredContent: {
|
package/dist/src/mcp/types.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { z } from
|
|
1
|
+
import { z } from "zod";
|
|
2
2
|
export const consultInputSchema = z.object({
|
|
3
|
-
prompt: z.string().min(1,
|
|
3
|
+
prompt: z.string().min(1, "Prompt is required."),
|
|
4
4
|
files: z.array(z.string()).default([]),
|
|
5
5
|
model: z.string().optional(),
|
|
6
6
|
models: z.array(z.string()).optional(),
|
|
7
|
-
engine: z.enum([
|
|
7
|
+
engine: z.enum(["api", "browser"]).optional(),
|
|
8
8
|
browserModelLabel: z.string().optional(),
|
|
9
|
-
browserAttachments: z.enum([
|
|
9
|
+
browserAttachments: z.enum(["auto", "never", "always"]).optional(),
|
|
10
10
|
browserBundleFiles: z.boolean().optional(),
|
|
11
|
-
browserThinkingTime: z.enum([
|
|
11
|
+
browserThinkingTime: z.enum(["light", "standard", "extended", "heavy"]).optional(),
|
|
12
12
|
browserKeepBrowser: z.boolean().optional(),
|
|
13
13
|
search: z.boolean().optional(),
|
|
14
14
|
slug: z.string().optional(),
|
package/dist/src/mcp/utils.js
CHANGED
|
@@ -1,25 +1,33 @@
|
|
|
1
|
-
import { resolveRunOptionsFromConfig } from
|
|
2
|
-
import { Launcher } from
|
|
1
|
+
import { resolveRunOptionsFromConfig } from "../cli/runOptions.js";
|
|
2
|
+
import { Launcher } from "chrome-launcher";
|
|
3
3
|
export function mapConsultToRunOptions({ prompt, files, model, models, engine, search, browserAttachments, browserBundleFiles, userConfig, env = process.env, }) {
|
|
4
4
|
// Normalize CLI-style inputs through the shared resolver so config/env defaults apply,
|
|
5
5
|
// then overlay MCP-only overrides such as explicit search toggles.
|
|
6
6
|
const mergedModels = Array.isArray(models) && models.length > 0
|
|
7
7
|
? [model, ...models].filter((entry) => Boolean(entry?.trim()))
|
|
8
8
|
: models;
|
|
9
|
-
const result = resolveRunOptionsFromConfig({
|
|
10
|
-
|
|
9
|
+
const result = resolveRunOptionsFromConfig({
|
|
10
|
+
prompt,
|
|
11
|
+
files,
|
|
12
|
+
model,
|
|
13
|
+
models: mergedModels,
|
|
14
|
+
engine,
|
|
15
|
+
userConfig,
|
|
16
|
+
env,
|
|
17
|
+
});
|
|
18
|
+
if (typeof search === "boolean") {
|
|
11
19
|
result.runOptions.search = search;
|
|
12
20
|
}
|
|
13
21
|
if (browserAttachments) {
|
|
14
22
|
result.runOptions.browserAttachments = browserAttachments;
|
|
15
23
|
}
|
|
16
|
-
if (typeof browserBundleFiles ===
|
|
24
|
+
if (typeof browserBundleFiles === "boolean") {
|
|
17
25
|
result.runOptions.browserBundleFiles = browserBundleFiles;
|
|
18
26
|
}
|
|
19
27
|
return result;
|
|
20
28
|
}
|
|
21
29
|
export function ensureBrowserAvailable(engine, options) {
|
|
22
|
-
if (engine !==
|
|
30
|
+
if (engine !== "browser") {
|
|
23
31
|
return null;
|
|
24
32
|
}
|
|
25
33
|
const remoteHost = options?.remoteHost?.trim() || process.env.ORACLE_REMOTE_HOST?.trim();
|
|
@@ -31,7 +39,7 @@ export function ensureBrowserAvailable(engine, options) {
|
|
|
31
39
|
}
|
|
32
40
|
const found = Launcher.getFirstInstallation();
|
|
33
41
|
if (!found) {
|
|
34
|
-
return
|
|
42
|
+
return "Browser engine unavailable: no Chrome installation found and CHROME_PATH is unset.";
|
|
35
43
|
}
|
|
36
44
|
return null;
|
|
37
45
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { APIConnectionError, APIConnectionTimeoutError } from
|
|
2
|
-
import chalk from
|
|
3
|
-
import { formatElapsed } from
|
|
4
|
-
import { startHeartbeat } from
|
|
5
|
-
import { OracleResponseError, OracleTransportError, describeTransportError, toTransportError, } from
|
|
1
|
+
import { APIConnectionError, APIConnectionTimeoutError } from "openai";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { formatElapsed } from "./format.js";
|
|
4
|
+
import { startHeartbeat } from "../heartbeat.js";
|
|
5
|
+
import { OracleResponseError, OracleTransportError, describeTransportError, toTransportError, } from "./errors.js";
|
|
6
6
|
const BACKGROUND_POLL_INTERVAL_MS = 5000;
|
|
7
7
|
const BACKGROUND_RETRY_BASE_MS = 3000;
|
|
8
8
|
const BACKGROUND_RETRY_MAX_MS = 15000;
|
|
@@ -18,10 +18,10 @@ export async function executeBackgroundResponse(params) {
|
|
|
18
18
|
throw transportError;
|
|
19
19
|
}
|
|
20
20
|
if (!initialResponse || !initialResponse.id) {
|
|
21
|
-
throw new OracleResponseError(
|
|
21
|
+
throw new OracleResponseError("API did not return a response ID for the background run.", initialResponse);
|
|
22
22
|
}
|
|
23
23
|
const responseId = initialResponse.id;
|
|
24
|
-
log(chalk.dim(`API scheduled background response ${responseId} (status=${initialResponse.status ??
|
|
24
|
+
log(chalk.dim(`API scheduled background response ${responseId} (status=${initialResponse.status ?? "unknown"}). Monitoring up to ${Math.round(maxWaitMs / 60000)} minutes for completion...`));
|
|
25
25
|
let heartbeatActive = false;
|
|
26
26
|
let stopHeartbeat = null;
|
|
27
27
|
const stopHeartbeatNow = () => {
|
|
@@ -66,29 +66,29 @@ async function pollBackgroundResponse(params) {
|
|
|
66
66
|
let lastStatus = response.status;
|
|
67
67
|
// biome-ignore lint/nursery/noUnnecessaryConditions: intentional polling loop.
|
|
68
68
|
while (true) {
|
|
69
|
-
const status = response.status ??
|
|
69
|
+
const status = response.status ?? "completed";
|
|
70
70
|
// firstCycle toggles immediately; keep for clarity in logs.
|
|
71
71
|
if (firstCycle) {
|
|
72
72
|
firstCycle = false;
|
|
73
73
|
log(chalk.dim(`API background response status=${status}. We'll keep retrying automatically.`));
|
|
74
74
|
}
|
|
75
|
-
else if (status !== lastStatus && status !==
|
|
75
|
+
else if (status !== lastStatus && status !== "completed") {
|
|
76
76
|
log(chalk.dim(`API background response status=${status}.`));
|
|
77
77
|
}
|
|
78
78
|
lastStatus = status;
|
|
79
|
-
if (status ===
|
|
79
|
+
if (status === "completed") {
|
|
80
80
|
return response;
|
|
81
81
|
}
|
|
82
|
-
if (status !==
|
|
82
|
+
if (status !== "in_progress" && status !== "queued") {
|
|
83
83
|
const detail = response.error?.message || response.incomplete_details?.reason || status;
|
|
84
84
|
throw new OracleResponseError(`Response did not complete: ${detail}`, response);
|
|
85
85
|
}
|
|
86
86
|
if (now() - startMark >= maxWaitMs) {
|
|
87
|
-
throw new OracleTransportError(
|
|
87
|
+
throw new OracleTransportError("client-timeout", "Timed out waiting for API background response to finish.");
|
|
88
88
|
}
|
|
89
89
|
await wait(BACKGROUND_POLL_INTERVAL_MS);
|
|
90
90
|
if (now() - startMark >= maxWaitMs) {
|
|
91
|
-
throw new OracleTransportError(
|
|
91
|
+
throw new OracleTransportError("client-timeout", "Timed out waiting for API background response to finish.");
|
|
92
92
|
}
|
|
93
93
|
const { response: nextResponse, reconnected } = await retrieveBackgroundResponseWithRetry({
|
|
94
94
|
client,
|
|
@@ -100,7 +100,7 @@ async function pollBackgroundResponse(params) {
|
|
|
100
100
|
log,
|
|
101
101
|
});
|
|
102
102
|
if (reconnected) {
|
|
103
|
-
const nextStatus = nextResponse.status ??
|
|
103
|
+
const nextStatus = nextResponse.status ?? "in_progress";
|
|
104
104
|
log(chalk.dim(`Reconnected to API background response (status=${nextStatus}). API is still working...`));
|
|
105
105
|
}
|
|
106
106
|
response = nextResponse;
|
|
@@ -125,7 +125,7 @@ async function retrieveBackgroundResponseWithRetry(params) {
|
|
|
125
125
|
log(chalk.yellow(`${describeTransportError(transportError, maxWaitMs)} Retrying in ${formatElapsed(delay)}...`));
|
|
126
126
|
await wait(delay);
|
|
127
127
|
if (now() - startMark >= maxWaitMs) {
|
|
128
|
-
throw new OracleTransportError(
|
|
128
|
+
throw new OracleTransportError("client-timeout", "Timed out waiting for API background response to finish.");
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
131
|
}
|