@steipete/oracle 0.13.0 → 0.14.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/README.md +20 -9
- package/dist/bin/oracle-cli.js +63 -63
- package/dist/docs-site/.nojekyll +0 -0
- package/dist/docs-site/CNAME +1 -0
- package/dist/docs-site/RELEASING.html +410 -0
- package/dist/docs-site/agents.html +374 -0
- package/dist/docs-site/anthropic.html +368 -0
- package/dist/docs-site/bridge.html +400 -0
- package/dist/docs-site/browser-mode.html +593 -0
- package/dist/docs-site/chromium-forks.html +347 -0
- package/dist/docs-site/cli-reference.html +346 -0
- package/dist/docs-site/configuration.html +452 -0
- package/dist/docs-site/favicon.svg +14 -0
- package/dist/docs-site/followup.html +375 -0
- package/dist/docs-site/gemini.html +383 -0
- package/dist/docs-site/grok.html +325 -0
- package/dist/docs-site/index.html +360 -0
- package/dist/docs-site/install.html +335 -0
- package/dist/docs-site/linux.html +321 -0
- package/dist/docs-site/llms.txt +43 -0
- package/dist/docs-site/manual-tests.html +596 -0
- package/dist/docs-site/mcp.html +391 -0
- package/dist/docs-site/multimodel.html +364 -0
- package/dist/docs-site/mythical-pro-agents.html +360 -0
- package/dist/docs-site/notifier.html +338 -0
- package/dist/docs-site/openai-endpoints.html +387 -0
- package/dist/docs-site/openrouter.html +344 -0
- package/dist/docs-site/quickstart.html +369 -0
- package/dist/docs-site/refactor/ux.html +532 -0
- package/dist/docs-site/sessions.html +388 -0
- package/dist/docs-site/social-card.png +0 -0
- package/dist/docs-site/social-card.svg +79 -0
- package/dist/docs-site/spec.html +363 -0
- package/dist/docs-site/testing.html +320 -0
- package/dist/docs-site/tui-debug.html +326 -0
- package/dist/docs-site/windows-work.html +323 -0
- package/dist/docs-site/windows.html +320 -0
- package/dist/src/browser/actions/assistantResponse.js +91 -9
- package/dist/src/browser/actions/deepResearch.js +180 -52
- package/dist/src/browser/actions/modelSelection.js +13 -11
- package/dist/src/browser/actions/navigation.js +294 -65
- package/dist/src/browser/actions/promptComposer.js +50 -4
- package/dist/src/browser/actions/thinkingTime.js +308 -89
- package/dist/src/browser/artifacts.js +19 -0
- package/dist/src/browser/chatgptFiles.js +797 -0
- package/dist/src/browser/chatgptImages.js +130 -3
- package/dist/src/browser/chromeLifecycle.js +4 -0
- package/dist/src/browser/config.js +2 -0
- package/dist/src/browser/index.js +347 -39
- package/dist/src/browser/pageActions.js +1 -1
- package/dist/src/browser/policies.js +2 -6
- package/dist/src/browser/projectSourcesRunner.js +14 -2
- package/dist/src/browser/prompt.js +11 -15
- package/dist/src/browser/reattach.js +6 -2
- package/dist/src/browser/reattachability.js +22 -10
- package/dist/src/browser/recoverConversation.js +73 -0
- package/dist/src/browser/sessionRunner.js +4 -1
- package/dist/src/cli/browserConfig.js +4 -1
- package/dist/src/cli/browserTabs.js +129 -54
- package/dist/src/cli/followup.js +72 -0
- package/dist/src/cli/help.js +1 -1
- package/dist/src/cli/options.js +16 -0
- package/dist/src/cli/reattachGuidance.js +8 -0
- package/dist/src/cli/runOptions.js +2 -12
- package/dist/src/cli/sessionCommand.js +4 -0
- package/dist/src/cli/sessionDisplay.js +17 -3
- package/dist/src/cli/sessionLineage.js +7 -4
- package/dist/src/cli/sessionRunner.js +16 -1
- package/dist/src/gemini-web/client.js +5 -10
- package/dist/src/gemini-web/executor.js +1 -24
- package/dist/src/gemini-web/models.js +83 -0
- package/dist/src/mcp/server.js +2 -0
- package/dist/src/mcp/tools/chatgptImage.js +127 -0
- package/dist/src/mcp/tools/consult.js +261 -167
- package/dist/src/mcp/types.js +2 -0
- package/dist/src/mcp/utils.js +87 -1
- package/dist/src/oracle/config.js +27 -1
- package/dist/src/oracle/files.js +4 -6
- package/dist/src/oracle/geminiModels.js +2 -0
- package/dist/src/oracle/markdown.js +36 -3
- package/dist/src/oracle/modelResolver.js +21 -13
- package/dist/src/oracle/promptAssembly.js +2 -4
- package/dist/src/oracle/request.js +3 -5
- package/dist/src/oracle/tokenStats.js +5 -1
- package/dist/src/oracle.js +1 -1
- package/dist/src/sessionManager.js +1 -0
- package/dist/vendor/oracle-notifier/OracleNotifier.app/Contents/CodeResources +0 -0
- package/dist/vendor/oracle-notifier/OracleNotifier.app/Contents/MacOS/OracleNotifier +0 -0
- package/package.json +19 -28
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/CodeResources +0 -0
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/MacOS/OracleNotifier +0 -0
package/dist/src/oracle/files.js
CHANGED
|
@@ -382,15 +382,13 @@ function relativePath(targetPath, cwd) {
|
|
|
382
382
|
const relative = path.relative(cwd, targetPath);
|
|
383
383
|
return relative || targetPath;
|
|
384
384
|
}
|
|
385
|
+
function formatLegacyFileSection(index, displayPath, content) {
|
|
386
|
+
return [`### File ${index}: ${displayPath}`, "```", content.trimEnd(), "```"].join("\n");
|
|
387
|
+
}
|
|
385
388
|
export function createFileSections(files, cwd = process.cwd()) {
|
|
386
389
|
return files.map((file, index) => {
|
|
387
390
|
const relative = toPosix(path.relative(cwd, file.path) || file.path);
|
|
388
|
-
const sectionText =
|
|
389
|
-
`### File ${index + 1}: ${relative}`,
|
|
390
|
-
"```",
|
|
391
|
-
file.content.trimEnd(),
|
|
392
|
-
"```",
|
|
393
|
-
].join("\n");
|
|
391
|
+
const sectionText = formatLegacyFileSection(index + 1, relative, file.content);
|
|
394
392
|
return {
|
|
395
393
|
index: index + 1,
|
|
396
394
|
absolutePath: file.path,
|
|
@@ -36,11 +36,44 @@ function pickFence(content) {
|
|
|
36
36
|
const fenceLength = Math.max(3, maxTicks + 1);
|
|
37
37
|
return "`".repeat(fenceLength);
|
|
38
38
|
}
|
|
39
|
-
|
|
39
|
+
function formatLineRange(lineCount) {
|
|
40
|
+
return lineCount === 0 ? "Lines: 0" : `Lines: 1-${lineCount}`;
|
|
41
|
+
}
|
|
42
|
+
function addLineNumbers(content) {
|
|
43
|
+
if (content.length === 0) {
|
|
44
|
+
return { text: "", lineCount: 0 };
|
|
45
|
+
}
|
|
46
|
+
const lines = content.split("\n");
|
|
47
|
+
const width = String(lines.length).length;
|
|
48
|
+
const numbered = lines
|
|
49
|
+
.map((line, index) => `${String(index + 1).padStart(width, " ")} | ${line}`)
|
|
50
|
+
.join("\n");
|
|
51
|
+
return { text: numbered, lineCount: lines.length };
|
|
52
|
+
}
|
|
53
|
+
function renderFileSection(displayPath, content, options) {
|
|
40
54
|
const fence = pickFence(content);
|
|
41
55
|
const lang = detectFenceLanguage(displayPath);
|
|
42
56
|
const normalized = content.replace(/\s+$/u, "");
|
|
43
|
-
const header =
|
|
57
|
+
const header = options.index == null
|
|
58
|
+
? `### File: ${displayPath}`
|
|
59
|
+
: `### File ${options.index}: ${displayPath}`;
|
|
44
60
|
const fenceOpen = lang ? `${fence}${lang}` : fence;
|
|
45
|
-
|
|
61
|
+
if (options.lineNumbers !== true) {
|
|
62
|
+
return [header, fenceOpen, normalized, fence, ""].join("\n");
|
|
63
|
+
}
|
|
64
|
+
const numbered = addLineNumbers(normalized);
|
|
65
|
+
return [header, formatLineRange(numbered.lineCount), fenceOpen, numbered.text, fence, ""].join("\n");
|
|
66
|
+
}
|
|
67
|
+
export function formatFileSection(displayPath, content, options = {}) {
|
|
68
|
+
return renderFileSection(displayPath, content, options);
|
|
69
|
+
}
|
|
70
|
+
export function formatFileSections(sections, options = {}) {
|
|
71
|
+
const lineNumbers = options.lineNumbers ?? true;
|
|
72
|
+
const rendered = sections
|
|
73
|
+
.map((section) => renderFileSection(section.displayPath, section.content, {
|
|
74
|
+
lineNumbers,
|
|
75
|
+
index: options.includeFileIndex ? section.index : undefined,
|
|
76
|
+
}).trimEnd())
|
|
77
|
+
.join("\n\n");
|
|
78
|
+
return options.trailingNewline && rendered ? `${rendered}\n` : rendered;
|
|
46
79
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { MODEL_CONFIGS, PRO_MODELS } from "./config.js";
|
|
3
|
-
import {
|
|
3
|
+
import { pricingFromUsdPerToken } from "tokentally";
|
|
4
4
|
const OPENROUTER_DEFAULT_BASE = "https://openrouter.ai/api/v1";
|
|
5
5
|
const OPENROUTER_MODELS_ENDPOINT = "https://openrouter.ai/api/v1/models";
|
|
6
6
|
const require = createRequire(import.meta.url);
|
|
@@ -42,6 +42,25 @@ export function normalizeOpenRouterBaseUrl(baseUrl) {
|
|
|
42
42
|
export function safeModelSlug(model) {
|
|
43
43
|
return model.replace(/[/\\]/g, "__").replace(/[:*?"<>|]/g, "_");
|
|
44
44
|
}
|
|
45
|
+
function openRouterPricing(pricing) {
|
|
46
|
+
const parsePrice = (value) => {
|
|
47
|
+
const parsed = typeof value === "number"
|
|
48
|
+
? value
|
|
49
|
+
: typeof value === "string" && value.trim() !== ""
|
|
50
|
+
? Number(value)
|
|
51
|
+
: NaN;
|
|
52
|
+
return Number.isFinite(parsed) && parsed >= 0 ? parsed : null;
|
|
53
|
+
};
|
|
54
|
+
const inputUsdPerToken = parsePrice(pricing?.prompt);
|
|
55
|
+
const outputUsdPerToken = parsePrice(pricing?.completion);
|
|
56
|
+
if (inputUsdPerToken === null || outputUsdPerToken === null)
|
|
57
|
+
return null;
|
|
58
|
+
const normalized = pricingFromUsdPerToken({ inputUsdPerToken, outputUsdPerToken });
|
|
59
|
+
return {
|
|
60
|
+
inputPerToken: normalized.inputUsdPerToken,
|
|
61
|
+
outputPerToken: normalized.outputUsdPerToken,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
45
64
|
const catalogCache = new Map();
|
|
46
65
|
const CACHE_TTL_MS = 5 * 60 * 1000;
|
|
47
66
|
const MAX_CACHE_ENTRIES = 20;
|
|
@@ -125,18 +144,7 @@ export async function resolveModelConfig(model, options = {}) {
|
|
|
125
144
|
openRouterId: targetId,
|
|
126
145
|
provider: known?.provider ?? "other",
|
|
127
146
|
inputLimit: info.context_length ?? known?.inputLimit ?? 200_000,
|
|
128
|
-
pricing: info.pricing
|
|
129
|
-
? (() => {
|
|
130
|
-
const pricing = pricingFromUsdPerMillion({
|
|
131
|
-
inputUsdPerMillion: info.pricing.prompt,
|
|
132
|
-
outputUsdPerMillion: info.pricing.completion,
|
|
133
|
-
});
|
|
134
|
-
return {
|
|
135
|
-
inputPerToken: pricing.inputUsdPerToken,
|
|
136
|
-
outputPerToken: pricing.outputUsdPerToken,
|
|
137
|
-
};
|
|
138
|
-
})()
|
|
139
|
-
: (known?.pricing ?? null),
|
|
147
|
+
pricing: openRouterPricing(info.pricing) ?? known?.pricing ?? null,
|
|
140
148
|
supportsBackground: known?.supportsBackground ?? true,
|
|
141
149
|
supportsSearch: known?.supportsSearch ?? true,
|
|
142
150
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { formatFileSections } from "./markdown.js";
|
|
2
2
|
/**
|
|
3
3
|
* Build the shared markdown structure for system/user/file sections.
|
|
4
4
|
* Collapses excessive blank lines and trims trailing whitespace to keep
|
|
@@ -6,9 +6,7 @@ import { formatFileSection } from "./markdown.js";
|
|
|
6
6
|
*/
|
|
7
7
|
export function buildPromptMarkdown(systemPrompt, userPrompt, sections) {
|
|
8
8
|
const lines = ["[SYSTEM]", systemPrompt, "", "[USER]", userPrompt, ""];
|
|
9
|
-
|
|
10
|
-
lines.push(formatFileSection(section.displayPath, section.content));
|
|
11
|
-
});
|
|
9
|
+
lines.push(formatFileSections(sections, { trailingNewline: true }));
|
|
12
10
|
return lines
|
|
13
11
|
.join("\n")
|
|
14
12
|
.replace(/\n{3,}/g, "\n\n")
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import { DEFAULT_SYSTEM_PROMPT } from "./config.js";
|
|
3
3
|
import { createFileSections, readFiles } from "./files.js";
|
|
4
|
-
import {
|
|
4
|
+
import { formatFileSections } from "./markdown.js";
|
|
5
5
|
import { createFsAdapter } from "./fsAdapter.js";
|
|
6
6
|
export function buildPrompt(basePrompt, files, cwd = process.cwd()) {
|
|
7
7
|
if (!files.length) {
|
|
8
8
|
return basePrompt;
|
|
9
9
|
}
|
|
10
10
|
const sections = createFileSections(files, cwd);
|
|
11
|
-
const sectionText = sections
|
|
11
|
+
const sectionText = formatFileSections(sections, { includeFileIndex: true });
|
|
12
12
|
return `${basePrompt.trim()}\n\n${sectionText}`;
|
|
13
13
|
}
|
|
14
14
|
export function buildRequestBody({ modelConfig, systemPrompt, userPrompt, searchEnabled, maxOutputTokens, background, storeResponse, previousResponseId, }) {
|
|
@@ -48,9 +48,7 @@ export async function renderPromptMarkdown(options, deps = {}) {
|
|
|
48
48
|
const userPrompt = (options.prompt ?? "").trim();
|
|
49
49
|
const lines = ["[SYSTEM]", systemPrompt, ""];
|
|
50
50
|
lines.push("[USER]", userPrompt, "");
|
|
51
|
-
|
|
52
|
-
lines.push(formatFileSection(section.displayPath, section.content));
|
|
53
|
-
});
|
|
51
|
+
lines.push(formatFileSections(sections));
|
|
54
52
|
return lines
|
|
55
53
|
.join("\n")
|
|
56
54
|
.replace(/\n{3,}/g, "\n\n")
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import { createFileSections } from "./files.js";
|
|
3
|
+
import { formatFileSections } from "./markdown.js";
|
|
3
4
|
export function getFileTokenStats(files, { cwd = process.cwd(), tokenizer, tokenizerOptions, inputTokenBudget, }) {
|
|
4
5
|
if (!files.length) {
|
|
5
6
|
return { stats: [], totalTokens: 0 };
|
|
@@ -7,7 +8,10 @@ export function getFileTokenStats(files, { cwd = process.cwd(), tokenizer, token
|
|
|
7
8
|
const sections = createFileSections(files, cwd);
|
|
8
9
|
const stats = sections
|
|
9
10
|
.map((section) => {
|
|
10
|
-
const
|
|
11
|
+
const sectionText = formatFileSections([section], {
|
|
12
|
+
includeFileIndex: true,
|
|
13
|
+
}).trimEnd();
|
|
14
|
+
const tokens = tokenizer(sectionText, tokenizerOptions);
|
|
11
15
|
const percent = inputTokenBudget ? (tokens / inputTokenBudget) * 100 : undefined;
|
|
12
16
|
return {
|
|
13
17
|
path: section.absolutePath,
|
package/dist/src/oracle.js
CHANGED
|
@@ -4,7 +4,7 @@ export { readFiles, createFileSections } from "./oracle/files.js";
|
|
|
4
4
|
export { buildPrompt, buildRequestBody, renderPromptMarkdown } from "./oracle/request.js";
|
|
5
5
|
export { estimateRequestTokens } from "./oracle/tokenEstimate.js";
|
|
6
6
|
export { formatUSD, formatNumber, formatElapsed } from "./oracle/format.js";
|
|
7
|
-
export { formatFileSection } from "./oracle/markdown.js";
|
|
7
|
+
export { formatFileSection, formatFileSections } from "./oracle/markdown.js";
|
|
8
8
|
export { getFileTokenStats, printFileTokenStats } from "./oracle/tokenStats.js";
|
|
9
9
|
export { OracleResponseError, OracleTransportError, OracleUserError, FileValidationError, BrowserAutomationError, PromptValidationError, describeTransportError, extractResponseMetadata, asOracleUserError, toTransportError, } from "./oracle/errors.js";
|
|
10
10
|
export { createDefaultClientFactory } from "./oracle/client.js";
|
|
@@ -228,6 +228,7 @@ export async function initializeSession(options, cwd, notifications, baseSlugOve
|
|
|
228
228
|
editImage: options.editImage,
|
|
229
229
|
outputPath: options.outputPath,
|
|
230
230
|
browserFollowUps: options.browserFollowUps,
|
|
231
|
+
browserResumeConversationUrl: options.browserResumeConversationUrl,
|
|
231
232
|
aspectRatio: options.aspectRatio,
|
|
232
233
|
geminiShowThoughts: options.geminiShowThoughts,
|
|
233
234
|
},
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@steipete/oracle",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "CLI wrapper around OpenAI Responses API with 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",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
60
|
"@anthropic-ai/tokenizer": "^0.0.4",
|
|
61
|
-
"@google/genai": "^2.0
|
|
61
|
+
"@google/genai": "^2.8.0",
|
|
62
62
|
"@google/generative-ai": "^0.24.1",
|
|
63
63
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
64
64
|
"@steipete/sweet-cookie": "^0.3.0",
|
|
@@ -66,38 +66,38 @@
|
|
|
66
66
|
"chrome-launcher": "^1.2.1",
|
|
67
67
|
"chrome-remote-interface": "^0.34.0",
|
|
68
68
|
"clipboardy": "^5.3.1",
|
|
69
|
-
"commander": "^
|
|
69
|
+
"commander": "^15.0.0",
|
|
70
70
|
"dotenv": "^17.4.2",
|
|
71
71
|
"fast-glob": "^3.3.3",
|
|
72
72
|
"gpt-tokenizer": "^3.4.0",
|
|
73
|
-
"inquirer": "
|
|
73
|
+
"inquirer": "14.0.2",
|
|
74
74
|
"json5": "^2.2.3",
|
|
75
75
|
"kleur": "^4.1.5",
|
|
76
76
|
"markdansi": "0.2.1",
|
|
77
|
-
"openai": "^6.
|
|
77
|
+
"openai": "^6.42.0",
|
|
78
78
|
"osc-progress": "^0.3.0",
|
|
79
|
-
"qs": "^6.15.
|
|
80
|
-
"shiki": "^4.0
|
|
79
|
+
"qs": "^6.15.2",
|
|
80
|
+
"shiki": "^4.2.0",
|
|
81
81
|
"toasted-notifier": "^10.1.0",
|
|
82
82
|
"tokentally": "^0.1.1",
|
|
83
|
-
"zod": "^4.4.
|
|
83
|
+
"zod": "^4.4.3"
|
|
84
84
|
},
|
|
85
85
|
"devDependencies": {
|
|
86
86
|
"@anthropic-ai/tokenizer": "^0.0.4",
|
|
87
87
|
"@types/chrome-remote-interface": "^0.34.0",
|
|
88
88
|
"@types/inquirer": "^9.0.9",
|
|
89
|
-
"@types/node": "^25.
|
|
90
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
91
|
-
"@vitest/coverage-v8": "4.1.
|
|
92
|
-
"devtools-protocol": "0.0.
|
|
93
|
-
"es-toolkit": "^1.
|
|
89
|
+
"@types/node": "^25.9.2",
|
|
90
|
+
"@typescript/native-preview": "7.0.0-dev.20260609.1",
|
|
91
|
+
"@vitest/coverage-v8": "4.1.8",
|
|
92
|
+
"devtools-protocol": "0.0.1643702",
|
|
93
|
+
"es-toolkit": "^1.47.0",
|
|
94
94
|
"esbuild": "^0.28.0",
|
|
95
|
-
"oxfmt": "0.
|
|
96
|
-
"oxlint": "^1.
|
|
97
|
-
"puppeteer-core": "^25.0
|
|
98
|
-
"tsx": "^4.
|
|
95
|
+
"oxfmt": "0.54.0",
|
|
96
|
+
"oxlint": "^1.69.0",
|
|
97
|
+
"puppeteer-core": "^25.1.0",
|
|
98
|
+
"tsx": "^4.22.4",
|
|
99
99
|
"typescript": "^6.0.3",
|
|
100
|
-
"vitest": "^4.1.
|
|
100
|
+
"vitest": "^4.1.8"
|
|
101
101
|
},
|
|
102
102
|
"devEngines": {
|
|
103
103
|
"runtime": [
|
|
@@ -110,14 +110,5 @@
|
|
|
110
110
|
"engines": {
|
|
111
111
|
"node": ">=24"
|
|
112
112
|
},
|
|
113
|
-
"packageManager": "pnpm@10.33.2"
|
|
114
|
-
"pnpm": {
|
|
115
|
-
"overrides": {
|
|
116
|
-
"devtools-protocol": "0.0.1629771",
|
|
117
|
-
"vite": "7.3.2"
|
|
118
|
-
},
|
|
119
|
-
"onlyBuiltDependencies": [
|
|
120
|
-
"esbuild"
|
|
121
|
-
]
|
|
122
|
-
}
|
|
113
|
+
"packageManager": "pnpm@10.33.2"
|
|
123
114
|
}
|
|
Binary file
|
|
Binary file
|