Compare commits
1 Commits
main
...
fix/main-c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cecadc3bbc |
@ -5,7 +5,7 @@ import { rawDataToString } from "../infra/ws.js";
|
|||||||
import { redactSensitiveText } from "../logging/redact.js";
|
import { redactSensitiveText } from "../logging/redact.js";
|
||||||
import { getDirectAgentForCdp, withNoProxyForCdpUrl } from "./cdp-proxy-bypass.js";
|
import { getDirectAgentForCdp, withNoProxyForCdpUrl } from "./cdp-proxy-bypass.js";
|
||||||
import { CDP_HTTP_REQUEST_TIMEOUT_MS, CDP_WS_HANDSHAKE_TIMEOUT_MS } from "./cdp-timeouts.js";
|
import { CDP_HTTP_REQUEST_TIMEOUT_MS, CDP_WS_HANDSHAKE_TIMEOUT_MS } from "./cdp-timeouts.js";
|
||||||
import { resolveBrowserRateLimitMessage } from "./client-fetch.js";
|
import { resolveBrowserRateLimitMessage } from "./rate-limit-message.js";
|
||||||
|
|
||||||
export { isLoopbackHost };
|
export { isLoopbackHost };
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import {
|
|||||||
createBrowserControlContext,
|
createBrowserControlContext,
|
||||||
startBrowserControlServiceFromConfig,
|
startBrowserControlServiceFromConfig,
|
||||||
} from "./control-service.js";
|
} from "./control-service.js";
|
||||||
|
import { resolveBrowserRateLimitMessage } from "./rate-limit-message.js";
|
||||||
import { createBrowserRouteDispatcher } from "./routes/dispatcher.js";
|
import { createBrowserRouteDispatcher } from "./routes/dispatcher.js";
|
||||||
|
|
||||||
// Application-level error from the browser control service (service is reachable
|
// Application-level error from the browser control service (service is reachable
|
||||||
@ -102,36 +103,10 @@ const BROWSER_TOOL_MODEL_HINT =
|
|||||||
"Do NOT retry the browser tool — it will keep failing. " +
|
"Do NOT retry the browser tool — it will keep failing. " +
|
||||||
"Use an alternative approach or inform the user that the browser is currently unavailable.";
|
"Use an alternative approach or inform the user that the browser is currently unavailable.";
|
||||||
|
|
||||||
const BROWSER_SERVICE_RATE_LIMIT_MESSAGE =
|
|
||||||
"Browser service rate limit reached. " +
|
|
||||||
"Wait for the current session to complete, or retry later.";
|
|
||||||
|
|
||||||
const BROWSERBASE_RATE_LIMIT_MESSAGE =
|
|
||||||
"Browserbase rate limit reached (max concurrent sessions). " +
|
|
||||||
"Wait for the current session to complete, or upgrade your plan.";
|
|
||||||
|
|
||||||
function isRateLimitStatus(status: number): boolean {
|
function isRateLimitStatus(status: number): boolean {
|
||||||
return status === 429;
|
return status === 429;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isBrowserbaseUrl(url: string): boolean {
|
|
||||||
if (!isAbsoluteHttp(url)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const host = new URL(url).hostname.toLowerCase();
|
|
||||||
return host === "browserbase.com" || host.endsWith(".browserbase.com");
|
|
||||||
} catch {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function resolveBrowserRateLimitMessage(url: string): string {
|
|
||||||
return isBrowserbaseUrl(url)
|
|
||||||
? BROWSERBASE_RATE_LIMIT_MESSAGE
|
|
||||||
: BROWSER_SERVICE_RATE_LIMIT_MESSAGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
function resolveBrowserFetchOperatorHint(url: string): string {
|
function resolveBrowserFetchOperatorHint(url: string): string {
|
||||||
const isLocal = !isAbsoluteHttp(url);
|
const isLocal = !isAbsoluteHttp(url);
|
||||||
return isLocal
|
return isLocal
|
||||||
|
|||||||
@ -1,7 +1,20 @@
|
|||||||
import type { OpenClawConfig } from "../config/config.js";
|
import type { OpenClawConfig } from "../config/config.js";
|
||||||
import { loadConfig } from "../config/config.js";
|
|
||||||
import { resolveGatewayAuth } from "../gateway/auth.js";
|
import { resolveGatewayAuth } from "../gateway/auth.js";
|
||||||
import { ensureGatewayStartupAuth } from "../gateway/startup-auth.js";
|
|
||||||
|
let configModulePromise: Promise<typeof import("../config/config.js")> | undefined;
|
||||||
|
let gatewayStartupAuthModulePromise:
|
||||||
|
| Promise<typeof import("../gateway/startup-auth.js")>
|
||||||
|
| undefined;
|
||||||
|
|
||||||
|
async function loadConfigModule() {
|
||||||
|
configModulePromise ??= import("../config/config.js");
|
||||||
|
return await configModulePromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadGatewayStartupAuthModule() {
|
||||||
|
gatewayStartupAuthModulePromise ??= import("../gateway/startup-auth.js");
|
||||||
|
return await gatewayStartupAuthModulePromise;
|
||||||
|
}
|
||||||
|
|
||||||
export type BrowserControlAuth = {
|
export type BrowserControlAuth = {
|
||||||
token?: string;
|
token?: string;
|
||||||
@ -67,6 +80,7 @@ export async function ensureBrowserControlAuth(params: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Re-read latest config to avoid racing with concurrent config writers.
|
// Re-read latest config to avoid racing with concurrent config writers.
|
||||||
|
const { loadConfig } = await loadConfigModule();
|
||||||
const latestCfg = loadConfig();
|
const latestCfg = loadConfig();
|
||||||
const latestAuth = resolveBrowserControlAuth(latestCfg, env);
|
const latestAuth = resolveBrowserControlAuth(latestCfg, env);
|
||||||
if (latestAuth.token || latestAuth.password) {
|
if (latestAuth.token || latestAuth.password) {
|
||||||
@ -82,6 +96,7 @@ export async function ensureBrowserControlAuth(params: {
|
|||||||
return { auth: latestAuth };
|
return { auth: latestAuth };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { ensureGatewayStartupAuth } = await loadGatewayStartupAuthModule();
|
||||||
const ensured = await ensureGatewayStartupAuth({
|
const ensured = await ensureGatewayStartupAuth({
|
||||||
cfg: latestCfg,
|
cfg: latestCfg,
|
||||||
env,
|
env,
|
||||||
|
|||||||
29
src/browser/rate-limit-message.ts
Normal file
29
src/browser/rate-limit-message.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
function isAbsoluteHttp(url: string): boolean {
|
||||||
|
return /^https?:\/\//i.test(url.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
function isBrowserbaseUrl(url: string): boolean {
|
||||||
|
if (!isAbsoluteHttp(url)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const host = new URL(url).hostname.toLowerCase();
|
||||||
|
return host === "browserbase.com" || host.endsWith(".browserbase.com");
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const BROWSER_SERVICE_RATE_LIMIT_MESSAGE =
|
||||||
|
"Browser service rate limit reached. " +
|
||||||
|
"Wait for the current session to complete, or retry later.";
|
||||||
|
|
||||||
|
const BROWSERBASE_RATE_LIMIT_MESSAGE =
|
||||||
|
"Browserbase rate limit reached (max concurrent sessions). " +
|
||||||
|
"Wait for the current session to complete, or upgrade your plan.";
|
||||||
|
|
||||||
|
export function resolveBrowserRateLimitMessage(url: string): string {
|
||||||
|
return isBrowserbaseUrl(url)
|
||||||
|
? BROWSERBASE_RATE_LIMIT_MESSAGE
|
||||||
|
: BROWSER_SERVICE_RATE_LIMIT_MESSAGE;
|
||||||
|
}
|
||||||
@ -36,7 +36,7 @@ describe("ensurePluginRegistryLoaded", () => {
|
|||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
mocks.loadConfig.mockReturnValue({
|
mocks.loadConfig.mockReturnValue({
|
||||||
plugins: { enabled: true },
|
plugins: { enabled: true },
|
||||||
channels: { telegram: { enabled: false } },
|
channels: { telegram: { botToken: "telegram-test-token" } },
|
||||||
});
|
});
|
||||||
mocks.loadPluginManifestRegistry.mockReturnValue({
|
mocks.loadPluginManifestRegistry.mockReturnValue({
|
||||||
plugins: [
|
plugins: [
|
||||||
|
|||||||
@ -177,8 +177,6 @@ export async function getStatusSummary(
|
|||||||
} = {},
|
} = {},
|
||||||
): Promise<StatusSummary> {
|
): Promise<StatusSummary> {
|
||||||
const { includeSensitive = true } = options;
|
const { includeSensitive = true } = options;
|
||||||
const { classifySessionKey, resolveContextTokensForModel, resolveSessionModelRef } =
|
|
||||||
await loadStatusSummaryRuntimeModule();
|
|
||||||
const cfg = options.config ?? (await loadConfigIoModule()).loadConfig();
|
const cfg = options.config ?? (await loadConfigIoModule()).loadConfig();
|
||||||
const needsChannelPlugins = hasPotentialConfiguredChannels(cfg);
|
const needsChannelPlugins = hasPotentialConfiguredChannels(cfg);
|
||||||
const linkContext = needsChannelPlugins
|
const linkContext = needsChannelPlugins
|
||||||
@ -196,6 +194,50 @@ export async function getStatusSummary(
|
|||||||
everyMs: summary.everyMs,
|
everyMs: summary.everyMs,
|
||||||
} satisfies HeartbeatStatus;
|
} satisfies HeartbeatStatus;
|
||||||
});
|
});
|
||||||
|
const mainSessionKey = resolveMainSessionKey(cfg);
|
||||||
|
const queuedSystemEvents = peekSystemEvents(mainSessionKey);
|
||||||
|
const agentStorePaths = agentList.agents.map((agent) => ({
|
||||||
|
agentId: agent.id,
|
||||||
|
path: resolveStorePath(cfg.session?.store, { agentId: agent.id }),
|
||||||
|
}));
|
||||||
|
const hasAnyStoredSessions = agentStorePaths.some(({ path }) => {
|
||||||
|
const store = readSessionStoreReadOnly(path);
|
||||||
|
return Object.keys(store).some((key) => key !== "global" && key !== "unknown");
|
||||||
|
});
|
||||||
|
|
||||||
|
if (
|
||||||
|
!needsChannelPlugins &&
|
||||||
|
!hasAnyStoredSessions &&
|
||||||
|
queuedSystemEvents.length === 0 &&
|
||||||
|
Object.keys(cfg).length === 0
|
||||||
|
) {
|
||||||
|
const summary: StatusSummary = {
|
||||||
|
runtimeVersion: resolveRuntimeServiceVersion(process.env),
|
||||||
|
heartbeat: {
|
||||||
|
defaultAgentId: agentList.defaultId,
|
||||||
|
agents: heartbeatAgents,
|
||||||
|
},
|
||||||
|
channelSummary: [],
|
||||||
|
queuedSystemEvents,
|
||||||
|
sessions: {
|
||||||
|
paths: agentStorePaths.map(({ path }) => path),
|
||||||
|
count: 0,
|
||||||
|
defaults: {
|
||||||
|
model: DEFAULT_MODEL,
|
||||||
|
contextTokens: DEFAULT_CONTEXT_TOKENS,
|
||||||
|
},
|
||||||
|
recent: [],
|
||||||
|
byAgent: agentStorePaths.map(({ agentId, path }) => ({
|
||||||
|
agentId,
|
||||||
|
path,
|
||||||
|
count: 0,
|
||||||
|
recent: [],
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return includeSensitive ? summary : redactSensitiveStatusSummary(summary);
|
||||||
|
}
|
||||||
|
|
||||||
const channelSummary = needsChannelPlugins
|
const channelSummary = needsChannelPlugins
|
||||||
? await loadChannelSummaryModule().then(({ buildChannelSummary }) =>
|
? await loadChannelSummaryModule().then(({ buildChannelSummary }) =>
|
||||||
buildChannelSummary(cfg, {
|
buildChannelSummary(cfg, {
|
||||||
@ -205,8 +247,8 @@ export async function getStatusSummary(
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
: [];
|
: [];
|
||||||
const mainSessionKey = resolveMainSessionKey(cfg);
|
const { classifySessionKey, resolveContextTokensForModel, resolveSessionModelRef } =
|
||||||
const queuedSystemEvents = peekSystemEvents(mainSessionKey);
|
await loadStatusSummaryRuntimeModule();
|
||||||
|
|
||||||
const resolved = resolveConfiguredStatusModelRef({
|
const resolved = resolveConfiguredStatusModelRef({
|
||||||
cfg,
|
cfg,
|
||||||
@ -295,13 +337,12 @@ export async function getStatusSummary(
|
|||||||
.sort((a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0));
|
.sort((a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0));
|
||||||
|
|
||||||
const paths = new Set<string>();
|
const paths = new Set<string>();
|
||||||
const byAgent = agentList.agents.map((agent) => {
|
const byAgent = agentStorePaths.map(({ agentId, path: storePath }) => {
|
||||||
const storePath = resolveStorePath(cfg.session?.store, { agentId: agent.id });
|
|
||||||
paths.add(storePath);
|
paths.add(storePath);
|
||||||
const store = loadStore(storePath);
|
const store = loadStore(storePath);
|
||||||
const sessions = buildSessionRows(store, { agentIdOverride: agent.id });
|
const sessions = buildSessionRows(store, { agentIdOverride: agentId });
|
||||||
return {
|
return {
|
||||||
agentId: agent.id,
|
agentId,
|
||||||
path: storePath,
|
path: storePath,
|
||||||
count: sessions.length,
|
count: sessions.length,
|
||||||
recent: sessions.slice(0, 10),
|
recent: sessions.slice(0, 10),
|
||||||
|
|||||||
@ -1,11 +1,17 @@
|
|||||||
import type { OpenClawConfig } from "../config/config.js";
|
import type { OpenClawConfig } from "../config/config.js";
|
||||||
import { resolveGatewayCredentialsWithSecretInputs } from "./call.js";
|
|
||||||
import {
|
import {
|
||||||
type ExplicitGatewayAuth,
|
type ExplicitGatewayAuth,
|
||||||
isGatewaySecretRefUnavailableError,
|
isGatewaySecretRefUnavailableError,
|
||||||
resolveGatewayProbeCredentialsFromConfig,
|
resolveGatewayProbeCredentialsFromConfig,
|
||||||
} from "./credentials.js";
|
} from "./credentials.js";
|
||||||
|
|
||||||
|
let gatewayCallModulePromise: Promise<typeof import("./call.js")> | undefined;
|
||||||
|
|
||||||
|
async function loadGatewayCallModule() {
|
||||||
|
gatewayCallModulePromise ??= import("./call.js");
|
||||||
|
return await gatewayCallModulePromise;
|
||||||
|
}
|
||||||
|
|
||||||
function buildGatewayProbeCredentialPolicy(params: {
|
function buildGatewayProbeCredentialPolicy(params: {
|
||||||
cfg: OpenClawConfig;
|
cfg: OpenClawConfig;
|
||||||
mode: "local" | "remote";
|
mode: "local" | "remote";
|
||||||
@ -40,6 +46,7 @@ export async function resolveGatewayProbeAuthWithSecretInputs(params: {
|
|||||||
explicitAuth?: ExplicitGatewayAuth;
|
explicitAuth?: ExplicitGatewayAuth;
|
||||||
}): Promise<{ token?: string; password?: string }> {
|
}): Promise<{ token?: string; password?: string }> {
|
||||||
const policy = buildGatewayProbeCredentialPolicy(params);
|
const policy = buildGatewayProbeCredentialPolicy(params);
|
||||||
|
const { resolveGatewayCredentialsWithSecretInputs } = await loadGatewayCallModule();
|
||||||
return await resolveGatewayCredentialsWithSecretInputs({
|
return await resolveGatewayCredentialsWithSecretInputs({
|
||||||
config: policy.config,
|
config: policy.config,
|
||||||
env: policy.env,
|
env: policy.env,
|
||||||
|
|||||||
@ -12,6 +12,14 @@ import {
|
|||||||
import { loadInternalHooks } from "./loader.js";
|
import { loadInternalHooks } from "./loader.js";
|
||||||
import { loadWorkspaceHookEntries } from "./workspace.js";
|
import { loadWorkspaceHookEntries } from "./workspace.js";
|
||||||
|
|
||||||
|
function canonicalizePathForAssertion(filePath: string): string {
|
||||||
|
try {
|
||||||
|
return fs.realpathSync.native(filePath);
|
||||||
|
} catch {
|
||||||
|
return path.resolve(filePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
describe("bundle plugin hooks", () => {
|
describe("bundle plugin hooks", () => {
|
||||||
let fixtureRoot = "";
|
let fixtureRoot = "";
|
||||||
let caseId = 0;
|
let caseId = 0;
|
||||||
@ -106,8 +114,8 @@ describe("bundle plugin hooks", () => {
|
|||||||
expect(entries[0]?.hook.name).toBe("bundle-hook");
|
expect(entries[0]?.hook.name).toBe("bundle-hook");
|
||||||
expect(entries[0]?.hook.source).toBe("openclaw-plugin");
|
expect(entries[0]?.hook.source).toBe("openclaw-plugin");
|
||||||
expect(entries[0]?.hook.pluginId).toBe("sample-bundle");
|
expect(entries[0]?.hook.pluginId).toBe("sample-bundle");
|
||||||
expect(entries[0]?.hook.baseDir).toBe(
|
expect(canonicalizePathForAssertion(entries[0]?.hook.baseDir ?? "")).toBe(
|
||||||
fs.realpathSync.native(path.join(bundleRoot, "hooks", "bundle-hook")),
|
canonicalizePathForAssertion(path.join(bundleRoot, "hooks", "bundle-hook")),
|
||||||
);
|
);
|
||||||
expect(entries[0]?.metadata?.events).toEqual(["command:new"]);
|
expect(entries[0]?.metadata?.events).toEqual(["command:new"]);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -36,7 +36,9 @@ function resolveDefaultLogDir(): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const DEFAULT_LOG_DIR = resolveDefaultLogDir();
|
export const DEFAULT_LOG_DIR = resolveDefaultLogDir();
|
||||||
export const DEFAULT_LOG_FILE = path.join(DEFAULT_LOG_DIR, "openclaw.log"); // legacy single-file path
|
export const DEFAULT_LOG_FILE = canUseNodeFs()
|
||||||
|
? path.join(DEFAULT_LOG_DIR, "openclaw.log")
|
||||||
|
: path.posix.join(DEFAULT_LOG_DIR, "openclaw.log"); // legacy single-file path
|
||||||
|
|
||||||
const LOG_PREFIX = "openclaw";
|
const LOG_PREFIX = "openclaw";
|
||||||
const LOG_SUFFIX = ".log";
|
const LOG_SUFFIX = ".log";
|
||||||
|
|||||||
@ -9,6 +9,10 @@ import { clearPluginManifestRegistryCache } from "./manifest-registry.js";
|
|||||||
|
|
||||||
const tempDirs: string[] = [];
|
const tempDirs: string[] = [];
|
||||||
|
|
||||||
|
async function canonicalizePathForAssertion(filePath: string): Promise<string> {
|
||||||
|
return await fs.realpath(filePath).catch(() => path.resolve(filePath));
|
||||||
|
}
|
||||||
|
|
||||||
async function createTempDir(prefix: string): Promise<string> {
|
async function createTempDir(prefix: string): Promise<string> {
|
||||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), prefix));
|
const dir = await fs.mkdtemp(path.join(os.tmpdir(), prefix));
|
||||||
tempDirs.push(dir);
|
tempDirs.push(dir);
|
||||||
@ -72,11 +76,16 @@ describe("loadEnabledBundleMcpConfig", () => {
|
|||||||
workspaceDir,
|
workspaceDir,
|
||||||
cfg: config,
|
cfg: config,
|
||||||
});
|
});
|
||||||
const resolvedServerPath = await fs.realpath(serverPath);
|
const loadedServerArgs = loaded.config.mcpServers.bundleProbe?.args;
|
||||||
|
const loadedServerPath = Array.isArray(loadedServerArgs) ? loadedServerArgs[0] : undefined;
|
||||||
|
|
||||||
expect(loaded.diagnostics).toEqual([]);
|
expect(loaded.diagnostics).toEqual([]);
|
||||||
expect(loaded.config.mcpServers.bundleProbe?.command).toBe("node");
|
expect(loaded.config.mcpServers.bundleProbe?.command).toBe("node");
|
||||||
expect(loaded.config.mcpServers.bundleProbe?.args).toEqual([resolvedServerPath]);
|
expect(Array.isArray(loadedServerArgs)).toBe(true);
|
||||||
|
expect(typeof loadedServerPath).toBe("string");
|
||||||
|
expect(await canonicalizePathForAssertion(String(loadedServerPath))).toBe(
|
||||||
|
await canonicalizePathForAssertion(serverPath),
|
||||||
|
);
|
||||||
} finally {
|
} finally {
|
||||||
env.restore();
|
env.restore();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,10 @@ vi.mock("./install.js", () => ({
|
|||||||
installPluginFromPath: (...args: unknown[]) => installPluginFromPathMock(...args),
|
installPluginFromPath: (...args: unknown[]) => installPluginFromPathMock(...args),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
function normalizePathForAssertion(value: string): string {
|
||||||
|
return value.replaceAll("\\", "/");
|
||||||
|
}
|
||||||
|
|
||||||
async function withTempDir<T>(fn: (dir: string) => Promise<T>): Promise<T> {
|
async function withTempDir<T>(fn: (dir: string) => Promise<T>): Promise<T> {
|
||||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-marketplace-test-"));
|
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-marketplace-test-"));
|
||||||
try {
|
try {
|
||||||
@ -45,9 +49,8 @@ describe("marketplace plugins", () => {
|
|||||||
|
|
||||||
const { listMarketplacePlugins } = await import("./marketplace.js");
|
const { listMarketplacePlugins } = await import("./marketplace.js");
|
||||||
const result = await listMarketplacePlugins({ marketplace: rootDir });
|
const result = await listMarketplacePlugins({ marketplace: rootDir });
|
||||||
expect(result).toEqual({
|
expect(result).toMatchObject({
|
||||||
ok: true,
|
ok: true,
|
||||||
sourceLabel: expect.stringContaining(".claude-plugin/marketplace.json"),
|
|
||||||
manifest: {
|
manifest: {
|
||||||
name: "Example Marketplace",
|
name: "Example Marketplace",
|
||||||
version: "1.0.0",
|
version: "1.0.0",
|
||||||
@ -61,6 +64,9 @@ describe("marketplace plugins", () => {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
expect(result.ok && normalizePathForAssertion(result.sourceLabel)).toContain(
|
||||||
|
".claude-plugin/marketplace.json",
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { isIP } from "node:net";
|
import { isIP } from "node:net";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { resolveSandboxConfigForAgent } from "../agents/sandbox.js";
|
import { resolveSandboxConfigForAgent } from "../agents/sandbox/config.js";
|
||||||
import { redactCdpUrl } from "../browser/cdp.helpers.js";
|
import { redactCdpUrl } from "../browser/cdp.helpers.js";
|
||||||
import { resolveBrowserConfig, resolveProfile } from "../browser/config.js";
|
import { resolveBrowserConfig, resolveProfile } from "../browser/config.js";
|
||||||
import { resolveBrowserControlAuth } from "../browser/control-auth.js";
|
import { resolveBrowserControlAuth } from "../browser/control-auth.js";
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user