@mind-harness/mh-browser 0.2.5 → 0.2.7
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/extension/manifest.json +1 -1
- package/extension/welcome.html +4 -0
- package/extension/welcome.js +10 -0
- package/lib/client.cjs +799 -254
- package/lib/index.js +2314 -1461
- package/lib/types/call.d.ts +23 -0
- package/lib/types/card.d.ts +1 -2
- package/lib/types/client.d.ts +20 -17
- package/lib/types/config.d.ts +25 -10
- package/lib/types/index.d.ts +23 -2
- package/lib/types/locales.d.ts +28 -2
- package/lib/types/location.d.ts +14 -0
- package/lib/types/location.js +3 -0
- package/lib/types/routes.d.ts +43 -0
- package/lib/types/row.d.ts +2 -4
- package/lib/types/service/browser.d.ts +16 -5
- package/lib/types/service/control.d.ts +5 -0
- package/lib/types/service/extension.d.ts +7 -0
- package/lib/types/service/launch-plan.d.ts +30 -0
- package/lib/types/service/locate.d.ts +81 -0
- package/lib/types/service/profile.d.ts +11 -0
- package/lib/types/service/service.d.ts +40 -6
- package/lib/types/service/test-hooks.d.ts +3 -0
- package/lib/types/settings-form.d.ts +142 -0
- package/lib/types/settings.d.ts +124 -0
- package/lib/types/typeprobe.d.ts +49 -0
- package/lib/types/types.d.ts +13 -1
- package/package.json +23 -30
- package/THIRD-PARTY-NOTICES +0 -23
- package/lib/typert.host.d.ts +0 -3
- package/lib/typert.host.js +0 -378
- package/lib/typert.remote-client.d.ts +0 -24
- package/lib/typert.remote-client.js +0 -52
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** One Host call from this package's client. Same shape the UI already reads. */
|
|
2
|
+
export type CallResult<T> = {
|
|
3
|
+
ok: true;
|
|
4
|
+
value: T;
|
|
5
|
+
} | {
|
|
6
|
+
ok: false;
|
|
7
|
+
error: {
|
|
8
|
+
code: string;
|
|
9
|
+
message: string;
|
|
10
|
+
details?: Record<string, unknown>;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
export interface CallInit {
|
|
14
|
+
method: 'GET' | 'POST';
|
|
15
|
+
body?: unknown;
|
|
16
|
+
query?: Record<string, string>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* `document.baseURI` keeps a mounted page on its prefix. dsh's file upload
|
|
20
|
+
* resolves the same way.
|
|
21
|
+
*/
|
|
22
|
+
export declare function call<T>(segment: string, init: CallInit, signal?: AbortSignal): Promise<CallResult<T>>;
|
|
23
|
+
//# sourceMappingURL=call.d.ts.map
|
package/lib/types/card.d.ts
CHANGED
|
@@ -15,10 +15,9 @@ export type RevealResult = {
|
|
|
15
15
|
};
|
|
16
16
|
export interface HandoverRowProps {
|
|
17
17
|
sessionId: string;
|
|
18
|
-
reason: string;
|
|
19
18
|
t: Translate;
|
|
20
19
|
reveal: (sessionId: string, signal: AbortSignal) => Promise<RevealResult>;
|
|
21
20
|
}
|
|
22
|
-
/** The open handover:
|
|
21
|
+
/** The open handover: a short line and the button that raises its window. */
|
|
23
22
|
export declare function HandoverRow(props: HandoverRowProps): ReactElement;
|
|
24
23
|
//# sourceMappingURL=card.d.ts.map
|
package/lib/types/client.d.ts
CHANGED
|
@@ -2,25 +2,19 @@ import { type ReactElement } from 'react';
|
|
|
2
2
|
import { type RevealResult } from './card.ts';
|
|
3
3
|
import { type Translate } from './locales.ts';
|
|
4
4
|
import { handoverRowDefinition } from './row.ts';
|
|
5
|
+
import type { SettingsFormScope } from './settings-form.ts';
|
|
6
|
+
import { type LocateFor } from './settings.ts';
|
|
5
7
|
/**
|
|
6
8
|
* Cordis services this client reads. `dsh.client.inject` is package load
|
|
7
|
-
* order, not this list.
|
|
9
|
+
* order, not this list.
|
|
8
10
|
*/
|
|
9
|
-
export declare const inject: readonly ["slots", "locale", "
|
|
10
|
-
export interface
|
|
11
|
+
export declare const inject: readonly ["slots", "locale", "uiConversation", "configForms"];
|
|
12
|
+
export interface MhBrowserApi {
|
|
11
13
|
revealHandover(sessionId: string, signal?: AbortSignal): Promise<RevealResult>;
|
|
14
|
+
locateFor: LocateFor;
|
|
12
15
|
}
|
|
13
|
-
interface RemoteCarrier {
|
|
14
|
-
$mount(contribution: object): Promise<() => Promise<void>>;
|
|
15
|
-
}
|
|
16
|
-
/** Props the session-scoped chat-node seat passes in. The session id is that seat's. */
|
|
17
16
|
export interface HostRowProps {
|
|
18
17
|
sessionId: string;
|
|
19
|
-
node: {
|
|
20
|
-
readonly data: {
|
|
21
|
-
readonly reason: string;
|
|
22
|
-
};
|
|
23
|
-
};
|
|
24
18
|
t: Translate;
|
|
25
19
|
}
|
|
26
20
|
export interface ClientHost {
|
|
@@ -31,23 +25,32 @@ export interface ClientHost {
|
|
|
31
25
|
key: string;
|
|
32
26
|
locale: string;
|
|
33
27
|
}, component: (props: HostRowProps) => ReactElement): () => void;
|
|
28
|
+
register(options: {
|
|
29
|
+
name: string;
|
|
30
|
+
key: string;
|
|
31
|
+
locale: string;
|
|
32
|
+
}, component: (props: {
|
|
33
|
+
t: Translate;
|
|
34
|
+
view?: 'summary' | 'page';
|
|
35
|
+
}) => ReactElement | null): () => void;
|
|
34
36
|
};
|
|
35
37
|
locale: {
|
|
36
38
|
register(ns: string, dicts: Record<'zh' | 'en', Record<string, string>>): () => void;
|
|
37
39
|
};
|
|
40
|
+
configForms: {
|
|
41
|
+
get<T>(entryId: string): SettingsFormScope<T>;
|
|
42
|
+
};
|
|
38
43
|
uiConversation: {
|
|
39
44
|
events: {
|
|
40
45
|
register(definition: typeof handoverRowDefinition): () => void;
|
|
41
46
|
};
|
|
42
47
|
};
|
|
43
48
|
effect(execute: () => () => void): unknown;
|
|
44
|
-
remote: RemoteCarrier & {
|
|
45
|
-
mhBrowser: MhBrowserRemote;
|
|
46
|
-
};
|
|
47
49
|
inject(names: readonly string[], apply: (ctx: ClientHost) => void): PromiseLike<unknown>;
|
|
48
50
|
}
|
|
51
|
+
/** Host calls used by the handover row and the settings lookup. */
|
|
52
|
+
export declare function browserApi(): MhBrowserApi;
|
|
49
53
|
export declare function apply(ctx: ClientHost): Promise<() => Promise<void>>;
|
|
50
54
|
/** Register the handover row. The tool call itself keeps the generic tool row. */
|
|
51
|
-
export declare function start(ctx: ClientHost): () => void;
|
|
52
|
-
export {};
|
|
55
|
+
export declare function start(ctx: ClientHost, api?: MhBrowserApi): () => void;
|
|
53
56
|
//# sourceMappingURL=client.d.ts.map
|
package/lib/types/config.d.ts
CHANGED
|
@@ -1,14 +1,27 @@
|
|
|
1
1
|
import z from '@deepseek-ai/schemastery';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
2
|
+
export declare const browserConfig: z<Schemastery.ObjectS<NoInfer<{
|
|
3
|
+
presence: z<Schemastery.ObjectS<NoInfer<{
|
|
4
|
+
maxBytes: z<number, number, "defined">;
|
|
5
|
+
}>>, Schemastery.ObjectT<NoInfer<{
|
|
6
|
+
maxBytes: z<number, number, "defined">;
|
|
7
|
+
}>>, "defined">;
|
|
8
|
+
browser: z<"auto" | "chrome" | "msedge" | "chromium", "auto" | "chrome" | "msedge" | "chromium", "volatile-defined">;
|
|
9
|
+
executablePath: z<string, string, "volatile">;
|
|
10
|
+
profileDir: z<string, string, "plain">;
|
|
11
|
+
headless: z<boolean, boolean, "defined">;
|
|
12
|
+
}>>, Schemastery.ObjectT<NoInfer<{
|
|
13
|
+
presence: z<Schemastery.ObjectS<NoInfer<{
|
|
14
|
+
maxBytes: z<number, number, "defined">;
|
|
15
|
+
}>>, Schemastery.ObjectT<NoInfer<{
|
|
16
|
+
maxBytes: z<number, number, "defined">;
|
|
17
|
+
}>>, "defined">;
|
|
18
|
+
browser: z<"auto" | "chrome" | "msedge" | "chromium", "auto" | "chrome" | "msedge" | "chromium", "volatile-defined">;
|
|
19
|
+
executablePath: z<string, string, "volatile">;
|
|
20
|
+
profileDir: z<string, string, "plain">;
|
|
21
|
+
headless: z<boolean, boolean, "defined">;
|
|
22
|
+
}>>, "plain">;
|
|
23
|
+
/** What {@link browserConfig} returns. `browser` and `executablePath` are read with `get()`. */
|
|
24
|
+
export type BrowserConfig = ReturnType<typeof browserConfig>;
|
|
12
25
|
/**
|
|
13
26
|
* Browser profile directory when the configuration names none. Each dsh profile gets its own:
|
|
14
27
|
* a browser profile directory admits one running browser, so two dsh profiles sharing one
|
|
@@ -17,4 +30,6 @@ export declare const browserConfig: z<BrowserConfig>;
|
|
|
17
30
|
export declare function defaultProfileDir(profile: {
|
|
18
31
|
name: string;
|
|
19
32
|
} | undefined, home?: string): string;
|
|
33
|
+
/** One subdirectory of the default profile root per browser, so logins do not cross browsers. */
|
|
34
|
+
export declare function profileDirFor(root: string, browser: string): string;
|
|
20
35
|
//# sourceMappingURL=config.d.ts.map
|
package/lib/types/index.d.ts
CHANGED
|
@@ -1,11 +1,32 @@
|
|
|
1
1
|
import type { Context } from '@deepseek-ai/cordis';
|
|
2
2
|
import type { BrowserConfig } from './config.ts';
|
|
3
|
+
import { browserConfig } from './config.ts';
|
|
3
4
|
import { MhBrowserService } from './service/service.ts';
|
|
4
5
|
export declare const name = "mh-browser";
|
|
5
6
|
export declare const inject: string[];
|
|
6
7
|
export type Config = BrowserConfig;
|
|
7
|
-
export declare const Config: import("@deepseek-ai/schemastery").default<
|
|
8
|
-
|
|
8
|
+
export declare const Config: import("@deepseek-ai/schemastery").default<Schemastery.ObjectS<NoInfer<{
|
|
9
|
+
presence: import("@deepseek-ai/schemastery").default<Schemastery.ObjectS<NoInfer<{
|
|
10
|
+
maxBytes: import("@deepseek-ai/schemastery").default<number, number, "defined">;
|
|
11
|
+
}>>, Schemastery.ObjectT<NoInfer<{
|
|
12
|
+
maxBytes: import("@deepseek-ai/schemastery").default<number, number, "defined">;
|
|
13
|
+
}>>, "defined">;
|
|
14
|
+
browser: import("@deepseek-ai/schemastery").default<"auto" | "chrome" | "msedge" | "chromium", "auto" | "chrome" | "msedge" | "chromium", "volatile-defined">;
|
|
15
|
+
executablePath: import("@deepseek-ai/schemastery").default<string, string, "volatile">;
|
|
16
|
+
profileDir: import("@deepseek-ai/schemastery").default<string, string, "plain">;
|
|
17
|
+
headless: import("@deepseek-ai/schemastery").default<boolean, boolean, "defined">;
|
|
18
|
+
}>>, Schemastery.ObjectT<NoInfer<{
|
|
19
|
+
presence: import("@deepseek-ai/schemastery").default<Schemastery.ObjectS<NoInfer<{
|
|
20
|
+
maxBytes: import("@deepseek-ai/schemastery").default<number, number, "defined">;
|
|
21
|
+
}>>, Schemastery.ObjectT<NoInfer<{
|
|
22
|
+
maxBytes: import("@deepseek-ai/schemastery").default<number, number, "defined">;
|
|
23
|
+
}>>, "defined">;
|
|
24
|
+
browser: import("@deepseek-ai/schemastery").default<"auto" | "chrome" | "msedge" | "chromium", "auto" | "chrome" | "msedge" | "chromium", "volatile-defined">;
|
|
25
|
+
executablePath: import("@deepseek-ai/schemastery").default<string, string, "volatile">;
|
|
26
|
+
profileDir: import("@deepseek-ai/schemastery").default<string, string, "plain">;
|
|
27
|
+
headless: import("@deepseek-ai/schemastery").default<boolean, boolean, "defined">;
|
|
28
|
+
}>>, "plain">;
|
|
29
|
+
export declare function apply(ctx: Context, config: Config | NonNullable<Parameters<typeof browserConfig>[0]>): Promise<void>;
|
|
9
30
|
export { MhBrowserService };
|
|
10
31
|
export { readAgentView } from './representation/agent-view.ts';
|
|
11
32
|
export type { AgentViewDoc, AgentViewLink, AgentViewRead } from './representation/agent-view.ts';
|
package/lib/types/locales.d.ts
CHANGED
|
@@ -1,11 +1,37 @@
|
|
|
1
1
|
/** Dictionary namespace for the handover row. */
|
|
2
2
|
export declare const NS = "mh-browser";
|
|
3
3
|
export declare const zh: {
|
|
4
|
-
readonly waiting: "
|
|
5
|
-
readonly reveal: "
|
|
4
|
+
readonly waiting: "这一步要你在浏览器里做";
|
|
5
|
+
readonly reveal: "打开浏览器里的页面";
|
|
6
6
|
readonly notHandingOver: "这次交接已经结束";
|
|
7
7
|
readonly noTab: "没有可以去的页面";
|
|
8
8
|
readonly failed: "没能切到浏览器";
|
|
9
|
+
readonly browserLabel: "浏览器";
|
|
10
|
+
readonly browserHint: "保存后,浏览器空闲时会关掉再按这个选择打开。已经打开的标签页会关掉。";
|
|
11
|
+
readonly pathLabel: "浏览器路径";
|
|
12
|
+
readonly pathHint: "留空就用自动找到的。可以填绝对路径,也可以用 ~。保存后同样在空闲时重启。";
|
|
13
|
+
readonly pathInvalid: "需要绝对路径,或以 ~ 开头";
|
|
14
|
+
readonly pathSearching: "正在查找…";
|
|
15
|
+
readonly pathMissing: "未找到{name},请填写路径";
|
|
16
|
+
readonly pathHelp: "说明";
|
|
17
|
+
readonly pathDoesNotExist: "不存在";
|
|
18
|
+
readonly pathIsDirectory: "是目录";
|
|
19
|
+
readonly pathDenied: "没有权限({code})";
|
|
20
|
+
readonly auto: "自动";
|
|
21
|
+
readonly browserUsing: "当前使用:{name}。";
|
|
22
|
+
readonly browserNone: "没有找到 Chrome 或 Edge。";
|
|
23
|
+
readonly installChrome: "安装 Chrome";
|
|
24
|
+
readonly chrome: "Google Chrome";
|
|
25
|
+
readonly msedge: "Microsoft Edge";
|
|
26
|
+
readonly chromium: "Chromium";
|
|
27
|
+
readonly overridden: "已覆盖";
|
|
28
|
+
readonly reset: "恢复";
|
|
29
|
+
readonly save: "保存";
|
|
30
|
+
readonly saving: "保存中";
|
|
31
|
+
readonly settingsUnavailable: "这个配置现在不可用";
|
|
32
|
+
readonly settingsReadOnly: "这次启动的配置不能在页面上改";
|
|
33
|
+
readonly settingsSaveFailed: "没有保存:设置可能在别处改过,或这个值不被接受。修改还在,检查后可以再保存";
|
|
34
|
+
readonly discard: "放弃修改";
|
|
9
35
|
};
|
|
10
36
|
export type CardKey = keyof typeof zh;
|
|
11
37
|
export declare const en: Record<CardKey, string>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Where a browser name resolves when no path is configured. */
|
|
2
|
+
import type { BrowserChoice, BrowserName } from './types.ts';
|
|
3
|
+
export type { BrowserChoice, BrowserName };
|
|
4
|
+
export interface BrowserLocationMiss {
|
|
5
|
+
path: string;
|
|
6
|
+
reason: string;
|
|
7
|
+
}
|
|
8
|
+
export type BrowserLocation = {
|
|
9
|
+
found: string;
|
|
10
|
+
browser?: BrowserName;
|
|
11
|
+
} | {
|
|
12
|
+
missing: BrowserLocationMiss[];
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=location.d.ts.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
3
|
+
import type { BrowserLocation } from './location.ts';
|
|
4
|
+
import { type BrowserChoice } from './types.ts';
|
|
5
|
+
interface ApiRouteHost {
|
|
6
|
+
webServer: {
|
|
7
|
+
register(route: {
|
|
8
|
+
kind: 'prefix';
|
|
9
|
+
path: string;
|
|
10
|
+
handler(req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
11
|
+
}): () => void;
|
|
12
|
+
};
|
|
13
|
+
connection: {
|
|
14
|
+
admit(request: {
|
|
15
|
+
headers: IncomingMessage['headers'];
|
|
16
|
+
}): {
|
|
17
|
+
readonly peer: unknown;
|
|
18
|
+
} | {
|
|
19
|
+
readonly rejection: 401 | 403;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
effect(execute: () => () => void): unknown;
|
|
23
|
+
}
|
|
24
|
+
export interface BrowserRouteHost extends ApiRouteHost {
|
|
25
|
+
mhBrowser: {
|
|
26
|
+
locateFor(browser: BrowserChoice, signal?: AbortSignal): Promise<BrowserLocation>;
|
|
27
|
+
revealHandover(sessionId: string, signal?: AbortSignal): Promise<{
|
|
28
|
+
status: 'revealed' | 'not-handing-over' | 'no-tab';
|
|
29
|
+
}>;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Routes for the browser client. A composition without `webServer` never
|
|
34
|
+
* starts this plugin; the browser tools do not depend on it.
|
|
35
|
+
*/
|
|
36
|
+
export declare const browserRoutesPlugin: {
|
|
37
|
+
name: string;
|
|
38
|
+
inject: readonly string[];
|
|
39
|
+
apply(ctx: Context): void;
|
|
40
|
+
};
|
|
41
|
+
export declare function registerBrowserRoutes(ctx: BrowserRouteHost): void;
|
|
42
|
+
export {};
|
|
43
|
+
//# sourceMappingURL=routes.d.ts.map
|
package/lib/types/row.d.ts
CHANGED
|
@@ -4,12 +4,10 @@
|
|
|
4
4
|
* the same key and hides the row; a hidden row is omitted from group order.
|
|
5
5
|
*/
|
|
6
6
|
export declare const HANDOVER_KIND = "browser-handover";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
7
|
+
/** The row carries no call payload. The reason stays on the question card. */
|
|
8
|
+
export type HandoverRowData = Record<string, never>;
|
|
10
9
|
interface OpenCall {
|
|
11
10
|
readonly callId: string;
|
|
12
|
-
readonly reason: string;
|
|
13
11
|
readonly seq: number;
|
|
14
12
|
}
|
|
15
13
|
export interface HandoverTurnState {
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import type { BrowserContext } from 'playwright';
|
|
2
|
+
import type { BrowserLocation } from '../location.ts';
|
|
2
3
|
import type { BrowserName } from '../types.ts';
|
|
4
|
+
import { type LocateEnv } from './locate.ts';
|
|
3
5
|
export interface LaunchOptions {
|
|
4
6
|
browser: BrowserName;
|
|
5
7
|
headless: boolean;
|
|
6
8
|
profileDir: string;
|
|
7
|
-
/**
|
|
9
|
+
/** Absolute path of the browser to launch. `~` is already expanded. */
|
|
8
10
|
executablePath?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Pass `channel`. False when a path was configured without naming a browser:
|
|
13
|
+
* the path is launched as itself.
|
|
14
|
+
*/
|
|
15
|
+
channel?: boolean;
|
|
9
16
|
}
|
|
10
17
|
/**
|
|
11
18
|
* Playwright appends `--no-sandbox` unless this is true, and branded Chrome
|
|
@@ -15,11 +22,15 @@ export interface LaunchOptions {
|
|
|
15
22
|
*/
|
|
16
23
|
export declare function chromiumSandboxEnabled(browser: BrowserName, platform?: NodeJS.Platform): boolean;
|
|
17
24
|
/**
|
|
18
|
-
* One persistent context for the whole process.
|
|
19
|
-
*
|
|
20
|
-
*
|
|
25
|
+
* One persistent context for the whole process. An installed browser is located
|
|
26
|
+
* here and passed as `executablePath`; `channel` names which install that was.
|
|
27
|
+
* `chromium` omits `channel` so Playwright uses its own browser unless a path
|
|
28
|
+
* is configured. A missing browser is reported and not downloaded. A launch
|
|
29
|
+
* that fails after the executable was found is reported as Playwright said.
|
|
21
30
|
*/
|
|
22
|
-
export declare function launchBrowser(options: LaunchOptions): Promise<BrowserContext>;
|
|
31
|
+
export declare function launchBrowser(options: LaunchOptions, env?: LocateEnv): Promise<BrowserContext>;
|
|
32
|
+
/** Playwright's own Chromium, or why that file cannot be run. */
|
|
33
|
+
export declare function bundledChromiumLocation(access: LocateEnv['access']): BrowserLocation;
|
|
23
34
|
/**
|
|
24
35
|
* Process id of the browser's main process. Playwright gives none for a
|
|
25
36
|
* persistent context. Asks the browser first; on POSIX the profile's
|
|
@@ -13,6 +13,11 @@ export declare class Control {
|
|
|
13
13
|
private readonly tabs;
|
|
14
14
|
private readonly since;
|
|
15
15
|
private readonly named;
|
|
16
|
+
/**
|
|
17
|
+
* A handover is waiting, or the person holds a tab. The browser is not
|
|
18
|
+
* restarted out from under either.
|
|
19
|
+
*/
|
|
20
|
+
busy(): boolean;
|
|
16
21
|
/** Whether the person holds any tab, or a handover is waiting. */
|
|
17
22
|
of(owner: string): 'model' | 'person';
|
|
18
23
|
/** The person holds this tab until they hand it back. */
|
|
@@ -11,6 +11,7 @@ export declare function extensionDir(): string;
|
|
|
11
11
|
export declare class Extension {
|
|
12
12
|
private readonly context;
|
|
13
13
|
private readonly id;
|
|
14
|
+
private readonly browserSession;
|
|
14
15
|
private workerPage;
|
|
15
16
|
private constructor();
|
|
16
17
|
static load(context: BrowserContext, browserSession: CDPSession): Promise<Extension>;
|
|
@@ -30,6 +31,12 @@ export declare class Extension {
|
|
|
30
31
|
private answer;
|
|
31
32
|
private worker;
|
|
32
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* The service worker, reloading the extension once when it is gone.
|
|
36
|
+
* A worker that comes back on its own during the first wait is used as it is.
|
|
37
|
+
* After a reload that still has no worker, the extension was turned off.
|
|
38
|
+
*/
|
|
39
|
+
export declare function restoreWorker(context: BrowserContext, id: string, reload: () => Promise<void>, signal?: AbortSignal, appearMs?: number): Promise<Worker>;
|
|
33
40
|
/** The extension's service worker. Looks once more after the wait times out. */
|
|
34
41
|
export declare function findWorker(context: BrowserContext, id: string, timeoutMs?: number): Promise<Worker>;
|
|
35
42
|
//# sourceMappingURL=extension.d.ts.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { BrowserLocation } from '../location.ts';
|
|
2
|
+
import type { BrowserChoice, BrowserName } from '../types.ts';
|
|
3
|
+
import { type LocateEnv } from './locate.ts';
|
|
4
|
+
/** What one launch uses. `channel` is false when the path does not name a browser channel. */
|
|
5
|
+
export interface LaunchPlan {
|
|
6
|
+
browser: BrowserName;
|
|
7
|
+
channel: boolean;
|
|
8
|
+
profileDir: string;
|
|
9
|
+
executablePath?: string;
|
|
10
|
+
/** Written after the browser starts. Absent when a path was given without naming a browser. */
|
|
11
|
+
remember?: BrowserName;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Which browser, path, and profile directory to launch.
|
|
15
|
+
* A configured path is checked and never replaced. Automatic selection keeps the
|
|
16
|
+
* remembered browser while it can be found, then Chrome, then Edge.
|
|
17
|
+
* Playwright's Chromium is used only when it is selected, or when it is the remembered one.
|
|
18
|
+
*/
|
|
19
|
+
export declare function planLaunch(input: {
|
|
20
|
+
choice: BrowserChoice;
|
|
21
|
+
configured: string | undefined;
|
|
22
|
+
root: string;
|
|
23
|
+
/** The default profile root gets one subdirectory per browser. A configured directory does not. */
|
|
24
|
+
split: boolean;
|
|
25
|
+
env: LocateEnv;
|
|
26
|
+
remembered: BrowserName | undefined;
|
|
27
|
+
bundled: BrowserLocation;
|
|
28
|
+
signal?: AbortSignal;
|
|
29
|
+
}): Promise<LaunchPlan>;
|
|
30
|
+
//# sourceMappingURL=launch-plan.d.ts.map
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { BrowserLocation, BrowserLocationMiss } from '../location.ts';
|
|
2
|
+
import type { BrowserName, MissingBrowser } from '../types.ts';
|
|
3
|
+
/** A browser the person installs. Playwright's Chromium is not located this way. */
|
|
4
|
+
export type InstalledBrowser = Exclude<BrowserName, 'chromium'>;
|
|
5
|
+
/** `ok`, or the errno from checking that the file can be executed. */
|
|
6
|
+
export type PathAccess = 'ok' | {
|
|
7
|
+
code: string;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Everything location reads from the machine. Tests pass a stand-in, so a
|
|
11
|
+
* case does not depend on what that machine has installed.
|
|
12
|
+
*/
|
|
13
|
+
export interface LocateEnv {
|
|
14
|
+
platform: NodeJS.Platform;
|
|
15
|
+
env: NodeJS.ProcessEnv;
|
|
16
|
+
home: string;
|
|
17
|
+
/** Whether `path` can be executed. */
|
|
18
|
+
access(path: string): PathAccess;
|
|
19
|
+
/**
|
|
20
|
+
* Paths from the platform's own lookup, already resolved. Called only after
|
|
21
|
+
* every fixed candidate missed. An empty list means the lookup found nothing
|
|
22
|
+
* or did not run.
|
|
23
|
+
*/
|
|
24
|
+
discover(browser: InstalledBrowser, signal?: AbortSignal): Promise<string[]>;
|
|
25
|
+
}
|
|
26
|
+
/** The fixed paths checked for `browser` on `env`, in the order they are tried. */
|
|
27
|
+
export declare function candidatePaths(browser: InstalledBrowser, env: LocateEnv): string[];
|
|
28
|
+
/**
|
|
29
|
+
* `configured` is used as given: a path that cannot be run is a failure, and
|
|
30
|
+
* nothing else is searched. `~` expands to `env.home`.
|
|
31
|
+
*/
|
|
32
|
+
export declare function checkConfigured(configured: string, env: LocateEnv): {
|
|
33
|
+
ok: true;
|
|
34
|
+
path: string;
|
|
35
|
+
} | {
|
|
36
|
+
ok: false;
|
|
37
|
+
path: string;
|
|
38
|
+
code: string;
|
|
39
|
+
};
|
|
40
|
+
/** Failure for a path the configuration names. */
|
|
41
|
+
export declare function configuredPathError(path: string, code: string): Error;
|
|
42
|
+
/** Chrome and Edge were both missed. The message asks for Chrome only. */
|
|
43
|
+
export declare class BrowserNotFoundError extends Error {
|
|
44
|
+
readonly notFound: MissingBrowser;
|
|
45
|
+
constructor(misses: {
|
|
46
|
+
browser: InstalledBrowser;
|
|
47
|
+
missing: BrowserLocationMiss[];
|
|
48
|
+
}[]);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The installed browser to launch when the choice is automatic.
|
|
52
|
+
* The remembered browser wins while it can still be found; otherwise Chrome, then Edge.
|
|
53
|
+
*/
|
|
54
|
+
export declare function resolveAuto(env: LocateEnv, remembered: BrowserName | undefined, signal?: AbortSignal): Promise<{
|
|
55
|
+
browser: InstalledBrowser;
|
|
56
|
+
path: string;
|
|
57
|
+
}>;
|
|
58
|
+
/** Failure listing every path that was tried. */
|
|
59
|
+
export declare function browserNotFoundError(browser: InstalledBrowser, missing: BrowserLocationMiss[]): Error;
|
|
60
|
+
/**
|
|
61
|
+
* The path to launch. A configured path is checked and never replaced.
|
|
62
|
+
* `chromium` without one returns undefined, so Playwright uses its own build.
|
|
63
|
+
* An installed browser that cannot be found throws.
|
|
64
|
+
*/
|
|
65
|
+
export declare function resolveExecutable(browser: BrowserName, configured: string | undefined, env: LocateEnv, signal?: AbortSignal): Promise<string | undefined>;
|
|
66
|
+
/**
|
|
67
|
+
* Where `browser` is installed when the configuration names no path.
|
|
68
|
+
* Fixed candidates first, then `env.discover`.
|
|
69
|
+
*/
|
|
70
|
+
export declare function locateInstalled(browser: InstalledBrowser, env: LocateEnv, signal?: AbortSignal): Promise<BrowserLocation>;
|
|
71
|
+
/** `path` is Playwright's Chromium. Missing or not executable is `missing`. */
|
|
72
|
+
export declare function locateBundled(path: string, access: LocateEnv['access']): BrowserLocation;
|
|
73
|
+
/** This machine: fixed paths, then Spotlight, App Paths, or `PATH`. */
|
|
74
|
+
export declare function hostLocateEnv(): LocateEnv;
|
|
75
|
+
/** A `.app` bundle path reported by Spotlight, turned into its executable. */
|
|
76
|
+
export declare function executableInApp(reported: string, binary: string): string | undefined;
|
|
77
|
+
/** The default value from `reg query ... /ve` output. */
|
|
78
|
+
export declare function regValue(stdout: string): string | undefined;
|
|
79
|
+
/** Text for an errno from {@link LocateEnv.access}. */
|
|
80
|
+
export declare function reasonForCode(code: string): string;
|
|
81
|
+
//# sourceMappingURL=locate.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { BrowserName } from '../types.ts';
|
|
2
|
+
/** The browser recorded after the last successful launch, if the file names one. */
|
|
3
|
+
export declare function readLastBrowser(root: string): Promise<BrowserName | undefined>;
|
|
4
|
+
/** Remember which browser actually launched, so automatic selection keeps using it. */
|
|
5
|
+
export declare function writeLastBrowser(root: string, browser: BrowserName): Promise<void>;
|
|
6
|
+
/**
|
|
7
|
+
* Move a profile that older versions kept in the root into `browser`'s subdirectory.
|
|
8
|
+
* A root without Chrome's `Local State`, or one whose subdirectory already exists, stays as it is.
|
|
9
|
+
*/
|
|
10
|
+
export declare function migrateLegacyProfile(root: string, browser: string): Promise<void>;
|
|
11
|
+
//# sourceMappingURL=profile.d.ts.map
|
|
@@ -1,15 +1,19 @@
|
|
|
1
|
-
import { Context } from '@deepseek-ai/cordis';
|
|
2
|
-
import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
|
|
1
|
+
import { Context, Service } from '@deepseek-ai/cordis';
|
|
3
2
|
import type { BrowserConfig } from '../config.ts';
|
|
3
|
+
import type { BrowserLocation } from '../location.ts';
|
|
4
4
|
import type { HeldPage, PresenceReceipt, PresenceRecord, PresenceSource } from '../presence/record.ts';
|
|
5
5
|
import type { PendingOp } from '../presence/fold.ts';
|
|
6
|
-
import type { Download, FetchResponseBody, InvokeCall, InvokeSent, PageError, PageOp, PageView, TabInfo, WaitFor } from '../types.ts';
|
|
6
|
+
import type { BrowserChoice, Download, FetchResponseBody, InvokeCall, InvokeSent, PageError, PageOp, PageView, TabInfo, WaitFor } from '../types.ts';
|
|
7
7
|
import { type Taken } from './control.ts';
|
|
8
8
|
import { testHooks, type TestHooks } from './test-hooks.ts';
|
|
9
9
|
declare module '@deepseek-ai/cordis' {
|
|
10
10
|
interface Context {
|
|
11
11
|
mhBrowser: MhBrowserService;
|
|
12
12
|
}
|
|
13
|
+
interface Events {
|
|
14
|
+
/** Volatile config was committed on this plugin fiber. Paths are key arrays. */
|
|
15
|
+
'loader/volatile-update'(paths: readonly (readonly string[])[]): void;
|
|
16
|
+
}
|
|
13
17
|
}
|
|
14
18
|
export type WriteTarget = {
|
|
15
19
|
root: string;
|
|
@@ -29,14 +33,27 @@ export interface HandBack extends Taken {
|
|
|
29
33
|
* the session's browser. `act` returns a snapshot, including on a page that
|
|
30
34
|
* also has an Agent View.
|
|
31
35
|
*/
|
|
32
|
-
export declare class MhBrowserService extends
|
|
33
|
-
static Config: import("@deepseek-ai/schemastery").default<BrowserConfig>;
|
|
36
|
+
export declare class MhBrowserService extends Service {
|
|
34
37
|
private readonly windows;
|
|
35
|
-
private readonly
|
|
38
|
+
private readonly headless;
|
|
39
|
+
/** Profile root. The default root gets one subdirectory per browser at launch. */
|
|
40
|
+
private readonly profileRoot;
|
|
41
|
+
/** A configured profile directory is used as given, without a per-browser subdirectory. */
|
|
42
|
+
private readonly splitProfile;
|
|
43
|
+
private readonly browserName;
|
|
44
|
+
private readonly executablePath;
|
|
45
|
+
/** Tests replace the machine lookup. Unset uses this machine. */
|
|
46
|
+
private locator;
|
|
36
47
|
private context;
|
|
37
48
|
private readonly pids;
|
|
38
49
|
private ready;
|
|
39
50
|
private closing;
|
|
51
|
+
/** A browser restart was requested and has not run yet. */
|
|
52
|
+
private relaunchWanted;
|
|
53
|
+
/** Counts browser and path changes. A start that sampled the latest one clears the restart. */
|
|
54
|
+
private configEpoch;
|
|
55
|
+
/** The running browser is being closed so the new configuration can start. */
|
|
56
|
+
private replacing;
|
|
40
57
|
/** The browser is not running. The next call that needs a page starts it. */
|
|
41
58
|
private exited;
|
|
42
59
|
private readonly exits;
|
|
@@ -112,6 +129,13 @@ export declare class MhBrowserService extends TypertRemoteService {
|
|
|
112
129
|
/** The person asked for the browser: start it if it exited, past the exit limit. */
|
|
113
130
|
startForPerson(): Promise<void>;
|
|
114
131
|
[testHooks](): TestHooks;
|
|
132
|
+
/**
|
|
133
|
+
* Where `browser` would be launched from when no path is configured.
|
|
134
|
+
* The configured path is not consulted: the answer is what an empty path uses.
|
|
135
|
+
* `auto` reports the browser automatic selection would launch.
|
|
136
|
+
*/
|
|
137
|
+
locateFor(browser: BrowserChoice, signal?: AbortSignal): Promise<BrowserLocation>;
|
|
138
|
+
private locateAuto;
|
|
115
139
|
act(owner: string, tab: string, op: PageOp, signal?: AbortSignal): Promise<PageView>;
|
|
116
140
|
holdHandover(owner: string, tab: string): void;
|
|
117
141
|
releaseHandover(owner: string): void;
|
|
@@ -152,6 +176,7 @@ export declare class MhBrowserService extends TypertRemoteService {
|
|
|
152
176
|
/**
|
|
153
177
|
* The person took over between turns. The next message they send is the
|
|
154
178
|
* hand-back. A handover that is still waiting on its card is not.
|
|
179
|
+
* The addresses are read before a waiting restart closes the pages.
|
|
155
180
|
*/
|
|
156
181
|
takePersonHandback(owner: string): HandBack | undefined;
|
|
157
182
|
/**
|
|
@@ -243,5 +268,14 @@ export declare class MhBrowserService extends TypertRemoteService {
|
|
|
243
268
|
private presenceUrls;
|
|
244
269
|
private snapshotNamed;
|
|
245
270
|
private exclusive;
|
|
271
|
+
private locateEnv;
|
|
272
|
+
private idle;
|
|
273
|
+
/**
|
|
274
|
+
* Close and start again when a configuration change is waiting and nothing
|
|
275
|
+
* is using the browser. A browser that is not running keeps the new values
|
|
276
|
+
* for the next start. The close is not counted as a crash.
|
|
277
|
+
*/
|
|
278
|
+
private relaunchIfIdle;
|
|
279
|
+
private replaceBrowser;
|
|
246
280
|
}
|
|
247
281
|
//# sourceMappingURL=service.d.ts.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { LocateEnv } from './locate.ts';
|
|
1
2
|
/** Key of the hooks tests use to crash the browser and reach a live page. Not exported by the package. */
|
|
2
3
|
export declare const testHooks: unique symbol;
|
|
3
4
|
export interface TestHooks {
|
|
@@ -9,5 +10,7 @@ export interface TestHooks {
|
|
|
9
10
|
pages(): unknown[];
|
|
10
11
|
/** The main browser process id recorded at start. */
|
|
11
12
|
pid(): number | undefined;
|
|
13
|
+
/** Use this lookup instead of the machine's. `undefined` restores the machine. */
|
|
14
|
+
useLocator(env: LocateEnv | undefined): void;
|
|
12
15
|
}
|
|
13
16
|
//# sourceMappingURL=test-hooks.d.ts.map
|