@steipete/oracle 0.9.0 → 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 +61 -48
- package/dist/bin/oracle-cli.js +455 -402
- 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 +275 -117
- package/dist/src/browser/actions/navigation.js +161 -137
- 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 +390 -295
- 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 +1 -1
- package/dist/src/browser/providers/chatgptDomProvider.js +9 -9
- package/dist/src/browser/providers/geminiDeepThinkDomProvider.js +51 -42
- package/dist/src/browser/providers/index.js +2 -2
- 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 +62 -48
- 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 +2 -2
- 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 +3 -3
- 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 +7 -7
- package/dist/src/cli/markdownRenderer.js +15 -15
- package/dist/src/cli/notifier.js +77 -67
- package/dist/src/cli/options.js +127 -106
- 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 +32 -28
- package/dist/src/cli/sessionCommand.js +31 -21
- package/dist/src/cli/sessionDisplay.js +95 -81
- package/dist/src/cli/sessionLineage.js +6 -2
- package/dist/src/cli/sessionRunner.js +103 -93
- package/dist/src/cli/sessionTable.js +26 -23
- package/dist/src/cli/stdin.js +22 -0
- package/dist/src/cli/tagline.js +121 -124
- package/dist/src/cli/tui/index.js +139 -128
- package/dist/src/cli/writeOutputPath.js +5 -5
- package/dist/src/config.js +7 -7
- package/dist/src/gemini-web/browserSessionManager.js +19 -15
- package/dist/src/gemini-web/client.js +76 -70
- package/dist/src/gemini-web/executionMode.js +6 -8
- package/dist/src/gemini-web/executor.js +98 -93
- package/dist/src/gemini-web/index.js +1 -1
- package/dist/src/mcp/server.js +16 -12
- package/dist/src/mcp/tools/consult.js +51 -47
- 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 +50 -41
- package/dist/src/oracle/config.js +96 -66
- package/dist/src/oracle/errors.js +38 -38
- package/dist/src/oracle/files.js +55 -46
- package/dist/src/oracle/finishLine.js +10 -8
- package/dist/src/oracle/format.js +3 -3
- package/dist/src/oracle/gemini.js +37 -33
- 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 +16 -13
- package/dist/src/oracle/run.js +156 -134
- 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 +77 -75
- package/dist/src/sessionStore.js +3 -3
- package/dist/src/version.js +10 -10
- package/dist/vendor/oracle-notifier/README.md +2 -0
- package/package.json +66 -62
- 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/types.js +0 -1
- 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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TOKENIZER_OPTIONS } from
|
|
1
|
+
import { TOKENIZER_OPTIONS } from "./config.js";
|
|
2
2
|
/**
|
|
3
3
|
* Estimate input tokens from the full request body instead of just system/user text.
|
|
4
4
|
* This is a conservative approximation: we tokenize the key textual fields and add a fixed buffer
|
|
@@ -12,7 +12,7 @@ export function estimateRequestTokens(requestBody, modelConfig, bufferTokens = 2
|
|
|
12
12
|
}
|
|
13
13
|
for (const turn of requestBody.input ?? []) {
|
|
14
14
|
for (const content of turn.content ?? []) {
|
|
15
|
-
if (typeof content.text ===
|
|
15
|
+
if (typeof content.text === "string") {
|
|
16
16
|
parts.push(content.text);
|
|
17
17
|
}
|
|
18
18
|
}
|
|
@@ -24,14 +24,14 @@ export function estimateRequestTokens(requestBody, modelConfig, bufferTokens = 2
|
|
|
24
24
|
parts.push(JSON.stringify(requestBody.reasoning));
|
|
25
25
|
}
|
|
26
26
|
if (requestBody.background) {
|
|
27
|
-
parts.push(
|
|
27
|
+
parts.push("background:true");
|
|
28
28
|
}
|
|
29
29
|
if (requestBody.store) {
|
|
30
|
-
parts.push(
|
|
30
|
+
parts.push("store:true");
|
|
31
31
|
}
|
|
32
|
-
const concatenated = parts.join(
|
|
32
|
+
const concatenated = parts.join("\n");
|
|
33
33
|
const baseEstimate = modelConfig.tokenizer(concatenated, TOKENIZER_OPTIONS);
|
|
34
|
-
const hasWebSearch = requestBody.tools?.some((tool) => tool?.type ===
|
|
34
|
+
const hasWebSearch = requestBody.tools?.some((tool) => tool?.type === "web_search_preview");
|
|
35
35
|
const searchBuffer = hasWebSearch ? SEARCH_RESULT_BUFFER_TOKENS : 0;
|
|
36
36
|
return baseEstimate + bufferTokens + searchBuffer;
|
|
37
37
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import chalk from
|
|
2
|
-
import { createFileSections } from
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { createFileSections } from "./files.js";
|
|
3
3
|
export function getFileTokenStats(files, { cwd = process.cwd(), tokenizer, tokenizerOptions, inputTokenBudget, }) {
|
|
4
4
|
if (!files.length) {
|
|
5
5
|
return { stats: [], totalTokens: 0 };
|
|
@@ -20,13 +20,13 @@ export function getFileTokenStats(files, { cwd = process.cwd(), tokenizer, token
|
|
|
20
20
|
const totalTokens = stats.reduce((sum, entry) => sum + entry.tokens, 0);
|
|
21
21
|
return { stats, totalTokens };
|
|
22
22
|
}
|
|
23
|
-
export function printFileTokenStats({ stats, totalTokens }, { inputTokenBudget, log = console.log }) {
|
|
23
|
+
export function printFileTokenStats({ stats, totalTokens }, { inputTokenBudget, log = console.log, }) {
|
|
24
24
|
if (!stats.length) {
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
27
|
-
log(chalk.bold(
|
|
27
|
+
log(chalk.bold("File Token Usage"));
|
|
28
28
|
for (const entry of stats) {
|
|
29
|
-
const percentLabel = inputTokenBudget && entry.percent != null ? `${entry.percent.toFixed(2)}%` :
|
|
29
|
+
const percentLabel = inputTokenBudget && entry.percent != null ? `${entry.percent.toFixed(2)}%` : "n/a";
|
|
30
30
|
log(`${entry.tokens.toLocaleString().padStart(10)} ${percentLabel.padStart(8)} ${entry.displayPath}`);
|
|
31
31
|
}
|
|
32
32
|
if (inputTokenBudget) {
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// Minimal helper to stringify arbitrary input for tokenizer consumption.
|
|
2
2
|
// Anthropic's tokenizer expects a string; we accept unknown and coerce safely.
|
|
3
3
|
export function stringifyTokenizerInput(input) {
|
|
4
|
-
if (typeof input ===
|
|
4
|
+
if (typeof input === "string")
|
|
5
5
|
return input;
|
|
6
6
|
if (input === null || input === undefined)
|
|
7
|
-
return
|
|
8
|
-
if (typeof input ===
|
|
7
|
+
return "";
|
|
8
|
+
if (typeof input === "number" || typeof input === "boolean" || typeof input === "bigint") {
|
|
9
9
|
return String(input);
|
|
10
10
|
}
|
|
11
|
-
if (typeof input ===
|
|
11
|
+
if (typeof input === "object") {
|
|
12
12
|
try {
|
|
13
13
|
return JSON.stringify(input);
|
|
14
14
|
}
|
|
@@ -16,7 +16,7 @@ export function stringifyTokenizerInput(input) {
|
|
|
16
16
|
// fall through to generic stringification
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
-
if (typeof input ===
|
|
19
|
+
if (typeof input === "function") {
|
|
20
20
|
return input.toString();
|
|
21
21
|
}
|
|
22
22
|
return String(input);
|
package/dist/src/oracle.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export { MODEL_CONFIGS, DEFAULT_MODEL, PRO_MODELS, DEFAULT_SYSTEM_PROMPT, TOKENIZER_OPTIONS, } from
|
|
3
|
-
export { readFiles, createFileSections } from
|
|
4
|
-
export { buildPrompt, buildRequestBody, renderPromptMarkdown } from
|
|
5
|
-
export { estimateRequestTokens } from
|
|
6
|
-
export { formatUSD, formatNumber, formatElapsed } from
|
|
7
|
-
export { formatFileSection } from
|
|
8
|
-
export { getFileTokenStats, printFileTokenStats } from
|
|
9
|
-
export { OracleResponseError, OracleTransportError, OracleUserError, FileValidationError, BrowserAutomationError, PromptValidationError, describeTransportError, extractResponseMetadata, asOracleUserError, toTransportError, } from
|
|
10
|
-
export { createDefaultClientFactory } from
|
|
11
|
-
export { runOracle, extractTextOutput } from
|
|
12
|
-
export { resolveGeminiModelId } from
|
|
1
|
+
export * from "./oracle/types.js";
|
|
2
|
+
export { MODEL_CONFIGS, DEFAULT_MODEL, PRO_MODELS, DEFAULT_SYSTEM_PROMPT, TOKENIZER_OPTIONS, } from "./oracle/config.js";
|
|
3
|
+
export { readFiles, createFileSections } from "./oracle/files.js";
|
|
4
|
+
export { buildPrompt, buildRequestBody, renderPromptMarkdown } from "./oracle/request.js";
|
|
5
|
+
export { estimateRequestTokens } from "./oracle/tokenEstimate.js";
|
|
6
|
+
export { formatUSD, formatNumber, formatElapsed } from "./oracle/format.js";
|
|
7
|
+
export { formatFileSection } from "./oracle/markdown.js";
|
|
8
|
+
export { getFileTokenStats, printFileTokenStats } from "./oracle/tokenStats.js";
|
|
9
|
+
export { OracleResponseError, OracleTransportError, OracleUserError, FileValidationError, BrowserAutomationError, PromptValidationError, describeTransportError, extractResponseMetadata, asOracleUserError, toTransportError, } from "./oracle/errors.js";
|
|
10
|
+
export { createDefaultClientFactory } from "./oracle/client.js";
|
|
11
|
+
export { runOracle, extractTextOutput } from "./oracle/run.js";
|
|
12
|
+
export { resolveGeminiModelId } from "./oracle/gemini.js";
|
package/dist/src/oracleHome.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import os from
|
|
2
|
-
import path from
|
|
1
|
+
import os from "node:os";
|
|
2
|
+
import path from "node:path";
|
|
3
3
|
let oracleHomeDirOverride = null;
|
|
4
4
|
/**
|
|
5
5
|
* Test-only hook: avoid mutating process.env (shared across Vitest worker threads).
|
|
@@ -9,5 +9,5 @@ export function setOracleHomeDirOverrideForTest(dir) {
|
|
|
9
9
|
oracleHomeDirOverride = dir;
|
|
10
10
|
}
|
|
11
11
|
export function getOracleHomeDir() {
|
|
12
|
-
return oracleHomeDirOverride ?? process.env.ORACLE_HOME_DIR ?? path.join(os.homedir(),
|
|
12
|
+
return oracleHomeDirOverride ?? process.env.ORACLE_HOME_DIR ?? path.join(os.homedir(), ".oracle");
|
|
13
13
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import http from
|
|
2
|
-
import path from
|
|
3
|
-
import { readFile } from
|
|
4
|
-
import { parseHostPort } from
|
|
1
|
+
import http from "node:http";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
import { parseHostPort } from "../bridge/connection.js";
|
|
5
5
|
export function createRemoteBrowserExecutor({ host, token }) {
|
|
6
6
|
// Return a drop-in replacement for runBrowserMode so the browser session runner can stay unchanged.
|
|
7
7
|
return async function remoteBrowserExecutor(options) {
|
|
@@ -20,11 +20,11 @@ export function createRemoteBrowserExecutor({ host, token }) {
|
|
|
20
20
|
const req = http.request({
|
|
21
21
|
hostname,
|
|
22
22
|
port,
|
|
23
|
-
path:
|
|
24
|
-
method:
|
|
23
|
+
path: "/runs",
|
|
24
|
+
method: "POST",
|
|
25
25
|
headers: {
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
"Content-Type": "application/json",
|
|
27
|
+
"Content-Length": body.length,
|
|
28
28
|
...(token ? { authorization: `Bearer ${token}` } : {}),
|
|
29
29
|
},
|
|
30
30
|
}, (res) => {
|
|
@@ -34,12 +34,12 @@ export function createRemoteBrowserExecutor({ host, token }) {
|
|
|
34
34
|
.catch(reject);
|
|
35
35
|
return;
|
|
36
36
|
}
|
|
37
|
-
res.setEncoding(
|
|
38
|
-
let buffer =
|
|
37
|
+
res.setEncoding("utf8");
|
|
38
|
+
let buffer = "";
|
|
39
39
|
let resolved = null;
|
|
40
|
-
res.on(
|
|
40
|
+
res.on("data", (chunk) => {
|
|
41
41
|
buffer += chunk;
|
|
42
|
-
let newlineIndex = buffer.indexOf(
|
|
42
|
+
let newlineIndex = buffer.indexOf("\n");
|
|
43
43
|
while (newlineIndex !== -1) {
|
|
44
44
|
const line = buffer.slice(0, newlineIndex).trim();
|
|
45
45
|
buffer = buffer.slice(newlineIndex + 1);
|
|
@@ -48,18 +48,18 @@ export function createRemoteBrowserExecutor({ host, token }) {
|
|
|
48
48
|
resolved = result;
|
|
49
49
|
}, reject);
|
|
50
50
|
}
|
|
51
|
-
newlineIndex = buffer.indexOf(
|
|
51
|
+
newlineIndex = buffer.indexOf("\n");
|
|
52
52
|
}
|
|
53
53
|
});
|
|
54
|
-
res.on(
|
|
54
|
+
res.on("end", () => {
|
|
55
55
|
if (resolved) {
|
|
56
56
|
resolve(resolved);
|
|
57
57
|
return;
|
|
58
58
|
}
|
|
59
|
-
reject(new Error(
|
|
59
|
+
reject(new Error("Remote browser run completed without a result."));
|
|
60
60
|
});
|
|
61
61
|
});
|
|
62
|
-
req.on(
|
|
62
|
+
req.on("error", reject);
|
|
63
63
|
req.write(body);
|
|
64
64
|
req.end();
|
|
65
65
|
});
|
|
@@ -74,7 +74,7 @@ async function serializeAttachments(attachments) {
|
|
|
74
74
|
fileName: path.basename(attachment.path),
|
|
75
75
|
displayPath: attachment.displayPath,
|
|
76
76
|
sizeBytes: attachment.sizeBytes,
|
|
77
|
-
contentBase64: content.toString(
|
|
77
|
+
contentBase64: content.toString("base64"),
|
|
78
78
|
});
|
|
79
79
|
}
|
|
80
80
|
return serialized;
|
|
@@ -96,26 +96,26 @@ function handleEvent(line, options, onResult, onError) {
|
|
|
96
96
|
onError(new Error(`Failed to parse remote event: ${error instanceof Error ? error.message : String(error)}`));
|
|
97
97
|
return;
|
|
98
98
|
}
|
|
99
|
-
if (event.type ===
|
|
99
|
+
if (event.type === "log") {
|
|
100
100
|
options.log?.(event.message);
|
|
101
101
|
return;
|
|
102
102
|
}
|
|
103
|
-
if (event.type ===
|
|
103
|
+
if (event.type === "error") {
|
|
104
104
|
onError(new Error(event.message));
|
|
105
105
|
return;
|
|
106
106
|
}
|
|
107
|
-
if (event.type ===
|
|
107
|
+
if (event.type === "result") {
|
|
108
108
|
onResult(event.result);
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
function collectError(res) {
|
|
112
112
|
return new Promise((resolve, reject) => {
|
|
113
113
|
const chunks = [];
|
|
114
|
-
res.on(
|
|
115
|
-
chunks.push(typeof chunk ===
|
|
114
|
+
res.on("data", (chunk) => {
|
|
115
|
+
chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
116
116
|
});
|
|
117
|
-
res.on(
|
|
118
|
-
const raw = Buffer.concat(chunks).toString(
|
|
117
|
+
res.on("end", () => {
|
|
118
|
+
const raw = Buffer.concat(chunks).toString("utf8");
|
|
119
119
|
try {
|
|
120
120
|
const parsed = JSON.parse(raw);
|
|
121
121
|
resolve(parsed.error ?? `Remote host responded with status ${res.statusCode}`);
|
|
@@ -124,6 +124,6 @@ function collectError(res) {
|
|
|
124
124
|
resolve(raw || `Remote host responded with status ${res.statusCode}`);
|
|
125
125
|
}
|
|
126
126
|
});
|
|
127
|
-
res.on(
|
|
127
|
+
res.on("error", reject);
|
|
128
128
|
});
|
|
129
129
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import http from
|
|
2
|
-
import net from
|
|
3
|
-
import { parseHostPort } from
|
|
1
|
+
import http from "node:http";
|
|
2
|
+
import net from "node:net";
|
|
3
|
+
import { parseHostPort } from "../bridge/connection.js";
|
|
4
4
|
export async function checkTcpConnection(host, timeoutMs = 2000) {
|
|
5
5
|
const { hostname, port } = parseHostPort(host);
|
|
6
6
|
return await new Promise((resolve) => {
|
|
@@ -24,14 +24,14 @@ export async function checkTcpConnection(host, timeoutMs = 2000) {
|
|
|
24
24
|
socket.unref();
|
|
25
25
|
};
|
|
26
26
|
socket.setTimeout(timeoutMs);
|
|
27
|
-
socket.once(
|
|
28
|
-
socket.once(
|
|
29
|
-
socket.once(
|
|
27
|
+
socket.once("error", onError);
|
|
28
|
+
socket.once("connect", onConnect);
|
|
29
|
+
socket.once("timeout", onTimeout);
|
|
30
30
|
});
|
|
31
31
|
}
|
|
32
32
|
export async function checkRemoteHealth({ host, token, timeoutMs = 5000, }) {
|
|
33
33
|
const { hostname, port } = parseHostPort(host);
|
|
34
|
-
const headers = { accept:
|
|
34
|
+
const headers = { accept: "application/json" };
|
|
35
35
|
if (token) {
|
|
36
36
|
headers.authorization = `Bearer ${token}`;
|
|
37
37
|
}
|
|
@@ -39,26 +39,26 @@ export async function checkRemoteHealth({ host, token, timeoutMs = 5000, }) {
|
|
|
39
39
|
const response = await requestJson({
|
|
40
40
|
hostname,
|
|
41
41
|
port,
|
|
42
|
-
path:
|
|
42
|
+
path: "/health",
|
|
43
43
|
headers,
|
|
44
44
|
timeoutMs,
|
|
45
45
|
});
|
|
46
|
-
if (response.statusCode === 200 && typeof response.json ===
|
|
46
|
+
if (response.statusCode === 200 && typeof response.json === "object" && response.json) {
|
|
47
47
|
const ok = response.json.ok === true;
|
|
48
48
|
const version = response.json.version;
|
|
49
49
|
const uptimeSeconds = response.json.uptimeSeconds;
|
|
50
50
|
return {
|
|
51
51
|
ok,
|
|
52
52
|
statusCode: response.statusCode,
|
|
53
|
-
version: typeof version ===
|
|
54
|
-
uptimeSeconds: typeof uptimeSeconds ===
|
|
53
|
+
version: typeof version === "string" ? version : undefined,
|
|
54
|
+
uptimeSeconds: typeof uptimeSeconds === "number" ? uptimeSeconds : undefined,
|
|
55
55
|
};
|
|
56
56
|
}
|
|
57
57
|
if (response.statusCode === 404) {
|
|
58
58
|
return {
|
|
59
59
|
ok: false,
|
|
60
60
|
statusCode: response.statusCode,
|
|
61
|
-
error:
|
|
61
|
+
error: "remote host does not expose /health (upgrade oracle on the host and retry)",
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
64
|
const error = extractErrorMessage(response.json, response.bodyText) ?? `HTTP ${response.statusCode}`;
|
|
@@ -69,9 +69,9 @@ export async function checkRemoteHealth({ host, token, timeoutMs = 5000, }) {
|
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
function extractErrorMessage(json, bodyText) {
|
|
72
|
-
if (json && typeof json ===
|
|
72
|
+
if (json && typeof json === "object") {
|
|
73
73
|
const err = json.error;
|
|
74
|
-
if (typeof err ===
|
|
74
|
+
if (typeof err === "string" && err.trim().length > 0) {
|
|
75
75
|
return err.trim();
|
|
76
76
|
}
|
|
77
77
|
}
|
|
@@ -84,15 +84,15 @@ async function requestJson({ hostname, port, path, headers, timeoutMs, }) {
|
|
|
84
84
|
hostname,
|
|
85
85
|
port,
|
|
86
86
|
path,
|
|
87
|
-
method:
|
|
87
|
+
method: "GET",
|
|
88
88
|
headers,
|
|
89
89
|
}, (res) => {
|
|
90
|
-
res.setEncoding(
|
|
91
|
-
let body =
|
|
92
|
-
res.on(
|
|
90
|
+
res.setEncoding("utf8");
|
|
91
|
+
let body = "";
|
|
92
|
+
res.on("data", (chunk) => {
|
|
93
93
|
body += chunk;
|
|
94
94
|
});
|
|
95
|
-
res.on(
|
|
95
|
+
res.on("end", () => {
|
|
96
96
|
const statusCode = res.statusCode ?? 0;
|
|
97
97
|
let json = null;
|
|
98
98
|
try {
|
|
@@ -107,7 +107,7 @@ async function requestJson({ hostname, port, path, headers, timeoutMs, }) {
|
|
|
107
107
|
req.setTimeout(timeoutMs, () => {
|
|
108
108
|
req.destroy(new Error(`timeout after ${timeoutMs}ms`));
|
|
109
109
|
});
|
|
110
|
-
req.on(
|
|
110
|
+
req.on("error", reject);
|
|
111
111
|
req.end();
|
|
112
112
|
});
|
|
113
113
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
function normalizeString(value) {
|
|
2
|
-
if (typeof value !==
|
|
2
|
+
if (typeof value !== "string")
|
|
3
3
|
return undefined;
|
|
4
4
|
const trimmed = value.trim();
|
|
5
5
|
return trimmed.length ? trimmed : undefined;
|
|
@@ -14,18 +14,18 @@ export function resolveRemoteServiceConfig({ cliHost, cliToken, userConfig, env
|
|
|
14
14
|
const host = cliHostValue ?? configBrowserHost ?? envHost;
|
|
15
15
|
const token = cliTokenValue ?? configBrowserToken ?? envToken;
|
|
16
16
|
const hostSource = cliHostValue
|
|
17
|
-
?
|
|
17
|
+
? "cli"
|
|
18
18
|
: configBrowserHost
|
|
19
|
-
?
|
|
19
|
+
? "config.browser"
|
|
20
20
|
: envHost
|
|
21
|
-
?
|
|
22
|
-
:
|
|
21
|
+
? "env"
|
|
22
|
+
: "unset";
|
|
23
23
|
const tokenSource = cliTokenValue
|
|
24
|
-
?
|
|
24
|
+
? "cli"
|
|
25
25
|
: configBrowserToken
|
|
26
|
-
?
|
|
26
|
+
? "config.browser"
|
|
27
27
|
: envToken
|
|
28
|
-
?
|
|
29
|
-
:
|
|
28
|
+
? "env"
|
|
29
|
+
: "unset";
|
|
30
30
|
return { host, token, sources: { host: hostSource, token: tokenSource } };
|
|
31
31
|
}
|