@mearl/native-host 2.5.0 → 2.5.1
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/dist/agentbay-browser.d.ts +47 -2
- package/dist/index.js +108 -14
- package/package.json +4 -4
|
@@ -9,6 +9,11 @@ export interface AgentBayBrowserRecord extends DaemonRecord {
|
|
|
9
9
|
name: string;
|
|
10
10
|
sessionId: string;
|
|
11
11
|
imageId?: string;
|
|
12
|
+
persistent?: boolean;
|
|
13
|
+
contextId?: string;
|
|
14
|
+
contextName?: string;
|
|
15
|
+
/** Successful context sync checkpoint for retrying deletion of the current session. */
|
|
16
|
+
contextSyncedAt?: string;
|
|
12
17
|
accessUrl?: string;
|
|
13
18
|
createdAt: string;
|
|
14
19
|
copiedCookies?: {
|
|
@@ -23,6 +28,16 @@ export interface AgentBaySessionLike {
|
|
|
23
28
|
initializeAsync(options: Record<string, unknown>): Promise<boolean>;
|
|
24
29
|
getEndpointUrl(): Promise<string>;
|
|
25
30
|
};
|
|
31
|
+
callMcpTool?(toolName: string, args: Record<string, unknown>, autoGenSession?: boolean): Promise<{
|
|
32
|
+
success?: boolean;
|
|
33
|
+
errorMessage?: string;
|
|
34
|
+
}>;
|
|
35
|
+
context?: {
|
|
36
|
+
sync(): Promise<{
|
|
37
|
+
success: boolean;
|
|
38
|
+
errorMessage?: string;
|
|
39
|
+
}>;
|
|
40
|
+
};
|
|
26
41
|
delete(syncContext?: boolean): Promise<{
|
|
27
42
|
success: boolean;
|
|
28
43
|
errorMessage?: string;
|
|
@@ -43,15 +58,34 @@ export interface AgentBayClientLike {
|
|
|
43
58
|
session?: AgentBaySessionLike;
|
|
44
59
|
errorMessage?: string;
|
|
45
60
|
}>;
|
|
61
|
+
context?: {
|
|
62
|
+
get(name: string, create?: boolean): Promise<{
|
|
63
|
+
success: boolean;
|
|
64
|
+
context?: {
|
|
65
|
+
id: string;
|
|
66
|
+
name: string;
|
|
67
|
+
};
|
|
68
|
+
errorMessage?: string;
|
|
69
|
+
}>;
|
|
70
|
+
delete(context: {
|
|
71
|
+
id: string;
|
|
72
|
+
name: string;
|
|
73
|
+
}): Promise<{
|
|
74
|
+
success: boolean;
|
|
75
|
+
errorMessage?: string;
|
|
76
|
+
}>;
|
|
77
|
+
};
|
|
46
78
|
}
|
|
47
79
|
export interface AgentBayBrowserSummary {
|
|
48
80
|
browserId: string;
|
|
49
81
|
name: string;
|
|
50
82
|
provider: 'agentbay';
|
|
51
83
|
headless: false;
|
|
52
|
-
persistent:
|
|
84
|
+
persistent: boolean;
|
|
53
85
|
agentbaySessionId: string;
|
|
54
86
|
agentbayImageId?: string;
|
|
87
|
+
agentbayContextId?: string;
|
|
88
|
+
agentbayContextName?: string;
|
|
55
89
|
agentbayAccessUrl?: string;
|
|
56
90
|
createdAt: string;
|
|
57
91
|
copiedCookies?: AgentBayBrowserRecord['copiedCookies'];
|
|
@@ -79,6 +113,7 @@ interface AgentBayBrowserSessionInitOptions {
|
|
|
79
113
|
export declare function agentBayBrowserId(name: string): string;
|
|
80
114
|
export declare function resolveAgentBayApiKey(): string;
|
|
81
115
|
export declare function resolveAgentBayImageId(value: unknown): string;
|
|
116
|
+
export declare function agentBayContextName(browserId: string): string;
|
|
82
117
|
export declare function normalizeDesktopUserAgent(value: unknown): string;
|
|
83
118
|
export declare function normalizeAgentBayAccessUrl(value: unknown): string | undefined;
|
|
84
119
|
export declare function hasAgentBayBrowser(selector: string): boolean;
|
|
@@ -87,5 +122,15 @@ export declare function resolveAgentBayEndpoint(sessionId: string): Promise<stri
|
|
|
87
122
|
export declare function keepAgentBaySessionAlive(sessionId: string): Promise<void>;
|
|
88
123
|
export declare function initializeAgentBayBrowserSession(session: Pick<AgentBaySessionLike, 'browser'>, input: Pick<BrowserLaunchParams, 'url'>, cookies: TransferableCookie[], options?: AgentBayBrowserSessionInitOptions): Promise<number>;
|
|
89
124
|
export declare function launchAgentBayBrowser(input: BrowserLaunchParams, deps: AgentBayBrowserManagerDeps): Promise<AgentBayBrowserSummary>;
|
|
90
|
-
export declare function
|
|
125
|
+
export declare function releaseAgentBayBrowserResources(record: AgentBayBrowserRecord, agentBay: AgentBayClientLike, options?: {
|
|
126
|
+
deleteProfile?: boolean;
|
|
127
|
+
persistRecord?: (record: AgentBayBrowserRecord) => void;
|
|
128
|
+
}): Promise<{
|
|
129
|
+
sessionDeleted: boolean;
|
|
130
|
+
contextSynced?: boolean;
|
|
131
|
+
contextDeleted?: boolean;
|
|
132
|
+
}>;
|
|
133
|
+
export declare function closeAgentBayBrowser(selector: string, options?: {
|
|
134
|
+
deleteProfile?: boolean;
|
|
135
|
+
}): Promise<Record<string, any>>;
|
|
91
136
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -9574,9 +9574,6 @@ function validateAgentBayInput(input) {
|
|
|
9574
9574
|
if (input.headless === true) {
|
|
9575
9575
|
throw new Error("headless=true is not supported by the AgentBay browser provider");
|
|
9576
9576
|
}
|
|
9577
|
-
if (input.persistent === true) {
|
|
9578
|
-
throw new Error("persistent is not supported by the AgentBay CDP provider yet");
|
|
9579
|
-
}
|
|
9580
9577
|
if (input.executablePath) {
|
|
9581
9578
|
throw new Error("executablePath is only supported by the local browser provider");
|
|
9582
9579
|
}
|
|
@@ -9592,6 +9589,9 @@ function resolveAgentBayImageId(value) {
|
|
|
9592
9589
|
}
|
|
9593
9590
|
return imageId;
|
|
9594
9591
|
}
|
|
9592
|
+
function agentBayContextName(browserId) {
|
|
9593
|
+
return `mearl-browser-${hashKey(browserId)}`;
|
|
9594
|
+
}
|
|
9595
9595
|
function normalizeDesktopUserAgent(value) {
|
|
9596
9596
|
const userAgent = typeof value === "string" ? value.trim() : "";
|
|
9597
9597
|
if (!userAgent) throw new Error("Could not determine the control browser user agent");
|
|
@@ -9614,9 +9614,11 @@ function browserSummary2(record2, running) {
|
|
|
9614
9614
|
name: record2.name,
|
|
9615
9615
|
provider: "agentbay",
|
|
9616
9616
|
headless: false,
|
|
9617
|
-
persistent:
|
|
9617
|
+
persistent: record2.persistent === true,
|
|
9618
9618
|
agentbaySessionId: record2.sessionId,
|
|
9619
9619
|
...record2.imageId ? { agentbayImageId: record2.imageId } : {},
|
|
9620
|
+
...record2.contextId ? { agentbayContextId: record2.contextId } : {},
|
|
9621
|
+
...record2.contextName ? { agentbayContextName: record2.contextName } : {},
|
|
9620
9622
|
...accessUrl ? { agentbayAccessUrl: accessUrl } : {},
|
|
9621
9623
|
createdAt: record2.createdAt,
|
|
9622
9624
|
...record2.copiedCookies ? { copiedCookies: record2.copiedCookies } : {},
|
|
@@ -9651,12 +9653,26 @@ function listAgentBayBrowsers() {
|
|
|
9651
9653
|
}
|
|
9652
9654
|
async function requireSession(sessionId, apiKey) {
|
|
9653
9655
|
const agentBay = await createClient(apiKey);
|
|
9656
|
+
return requireSessionFromClient(agentBay, sessionId);
|
|
9657
|
+
}
|
|
9658
|
+
async function requireSessionFromClient(agentBay, sessionId) {
|
|
9654
9659
|
const result = await agentBay.get(sessionId);
|
|
9655
9660
|
if (!result.success || !result.session) {
|
|
9656
9661
|
throw new Error(result.errorMessage || `AgentBay session not found: ${sessionId}`);
|
|
9657
9662
|
}
|
|
9658
9663
|
return result.session;
|
|
9659
9664
|
}
|
|
9665
|
+
async function resolvePersistentContext(agentBay, browserId) {
|
|
9666
|
+
if (!agentBay.context) {
|
|
9667
|
+
throw new Error("The installed AgentBay SDK does not support persistent browser contexts");
|
|
9668
|
+
}
|
|
9669
|
+
const name = agentBayContextName(browserId);
|
|
9670
|
+
const result = await agentBay.context.get(name, true);
|
|
9671
|
+
if (!result.success || !result.context?.id) {
|
|
9672
|
+
throw new Error(result.errorMessage || `Failed to create AgentBay browser context: ${name}`);
|
|
9673
|
+
}
|
|
9674
|
+
return { id: result.context.id, name: result.context.name || name };
|
|
9675
|
+
}
|
|
9660
9676
|
async function resolveAgentBayEndpoint(sessionId) {
|
|
9661
9677
|
const apiKey = resolveAgentBayApiKey();
|
|
9662
9678
|
const { AgentBay, GetCdpLinkRequest } = await loadSdk();
|
|
@@ -9702,12 +9718,14 @@ async function launchAgentBayBrowser(input, deps) {
|
|
|
9702
9718
|
const browserId = agentBayBrowserId(name);
|
|
9703
9719
|
validateAgentBayInput(input);
|
|
9704
9720
|
const imageId = resolveAgentBayImageId(input.imageId);
|
|
9721
|
+
const persistent = input.persistent === true;
|
|
9705
9722
|
const userAgentMode = resolveUserAgentMode(input.userAgentMode);
|
|
9706
9723
|
const copyCookieDomains = input.copyCookieDomains === void 0 ? [] : normalizeCookieDomains(input.copyCookieDomains);
|
|
9707
9724
|
const apiKey = (deps.resolveApiKey ?? resolveAgentBayApiKey)();
|
|
9708
9725
|
const releaseLock = acquireLaunchLock(browserId);
|
|
9709
9726
|
const persistBrowserRecord = deps.persistBrowserRecord ?? ((record2) => writeRecord(keyedConfigFile(AGENTBAY_BROWSERS_SUBDIR, record2.browserId), record2));
|
|
9710
9727
|
let session = null;
|
|
9728
|
+
let context;
|
|
9711
9729
|
let hostPid = 0;
|
|
9712
9730
|
let recordWritten = false;
|
|
9713
9731
|
try {
|
|
@@ -9717,7 +9735,18 @@ async function launchAgentBayBrowser(input, deps) {
|
|
|
9717
9735
|
userAgentMode === "desktop" ? deps.getBrowserUserAgent().then(normalizeDesktopUserAgent) : Promise.resolve(void 0)
|
|
9718
9736
|
]);
|
|
9719
9737
|
const agentBay = await (deps.createAgentBayClient ?? createClient)(apiKey);
|
|
9720
|
-
|
|
9738
|
+
context = persistent ? await resolvePersistentContext(agentBay, browserId) : void 0;
|
|
9739
|
+
const created = await agentBay.create({
|
|
9740
|
+
imageId,
|
|
9741
|
+
framework: "mearl",
|
|
9742
|
+
...context ? {
|
|
9743
|
+
browserContext: {
|
|
9744
|
+
contextId: context.id,
|
|
9745
|
+
autoUpload: true,
|
|
9746
|
+
syncMode: "standard"
|
|
9747
|
+
}
|
|
9748
|
+
} : {}
|
|
9749
|
+
});
|
|
9721
9750
|
if (!created.success || !created.session) {
|
|
9722
9751
|
throw new Error(created.errorMessage || "AgentBay session creation failed");
|
|
9723
9752
|
}
|
|
@@ -9757,6 +9786,8 @@ async function launchAgentBayBrowser(input, deps) {
|
|
|
9757
9786
|
name,
|
|
9758
9787
|
sessionId: session.sessionId,
|
|
9759
9788
|
imageId,
|
|
9789
|
+
persistent,
|
|
9790
|
+
...context ? { contextId: context.id, contextName: context.name } : {},
|
|
9760
9791
|
...accessUrl ? { accessUrl } : {},
|
|
9761
9792
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9762
9793
|
...copyCookieDomains.length > 0 ? { copiedCookies: { domains: copyCookieDomains, count: copiedCookieCount } } : {}
|
|
@@ -9790,6 +9821,8 @@ async function launchAgentBayBrowser(input, deps) {
|
|
|
9790
9821
|
name,
|
|
9791
9822
|
sessionId: session.sessionId,
|
|
9792
9823
|
imageId,
|
|
9824
|
+
persistent,
|
|
9825
|
+
...context ? { contextId: context.id, contextName: context.name } : {},
|
|
9793
9826
|
...accessUrl ? { accessUrl } : {},
|
|
9794
9827
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
9795
9828
|
};
|
|
@@ -9827,16 +9860,72 @@ function isMissingSessionError(error48) {
|
|
|
9827
9860
|
const message = error48 instanceof Error ? error48.message : String(error48);
|
|
9828
9861
|
return /not[ -]?found|does not exist|already deleted|invalid session/i.test(message);
|
|
9829
9862
|
}
|
|
9830
|
-
async function
|
|
9831
|
-
const
|
|
9832
|
-
|
|
9863
|
+
async function releaseAgentBayBrowserResources(record2, agentBay, options = {}) {
|
|
9864
|
+
const deleteContext = record2.persistent === true && options.deleteProfile === true;
|
|
9865
|
+
const syncContext = record2.persistent === true && !deleteContext;
|
|
9866
|
+
let contextSynced = Boolean(record2.contextSyncedAt);
|
|
9867
|
+
let session;
|
|
9833
9868
|
try {
|
|
9834
|
-
|
|
9835
|
-
const result = await session.delete(false);
|
|
9836
|
-
if (!result.success) throw new Error(result.errorMessage || "AgentBay session deletion failed");
|
|
9869
|
+
session = await requireSessionFromClient(agentBay, record2.sessionId);
|
|
9837
9870
|
} catch (error48) {
|
|
9838
9871
|
if (!isMissingSessionError(error48)) throw error48;
|
|
9839
9872
|
}
|
|
9873
|
+
if (session) {
|
|
9874
|
+
if (syncContext && !contextSynced) {
|
|
9875
|
+
if (!session.callMcpTool) {
|
|
9876
|
+
throw new Error("The installed AgentBay SDK cannot stop the browser before context sync");
|
|
9877
|
+
}
|
|
9878
|
+
const stopped = await session.callMcpTool("stopChrome", {}, false);
|
|
9879
|
+
if (stopped.success === false) {
|
|
9880
|
+
throw new Error(stopped.errorMessage || "AgentBay browser shutdown failed");
|
|
9881
|
+
}
|
|
9882
|
+
if (!session.context) {
|
|
9883
|
+
throw new Error("The installed AgentBay SDK cannot synchronize browser context state");
|
|
9884
|
+
}
|
|
9885
|
+
const synced = await session.context.sync();
|
|
9886
|
+
if (!synced.success) {
|
|
9887
|
+
throw new Error(synced.errorMessage || "AgentBay browser context sync failed");
|
|
9888
|
+
}
|
|
9889
|
+
contextSynced = true;
|
|
9890
|
+
record2.contextSyncedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9891
|
+
options.persistRecord?.(record2);
|
|
9892
|
+
}
|
|
9893
|
+
try {
|
|
9894
|
+
const result = await session.delete(false);
|
|
9895
|
+
if (!result.success) {
|
|
9896
|
+
throw new Error(result.errorMessage || "AgentBay session deletion failed");
|
|
9897
|
+
}
|
|
9898
|
+
} catch (error48) {
|
|
9899
|
+
if (!isMissingSessionError(error48)) throw error48;
|
|
9900
|
+
}
|
|
9901
|
+
}
|
|
9902
|
+
if (deleteContext) {
|
|
9903
|
+
if (!record2.contextId || !record2.contextName || !agentBay.context) {
|
|
9904
|
+
throw new Error("AgentBay browser context metadata is unavailable for profile deletion");
|
|
9905
|
+
}
|
|
9906
|
+
const result = await agentBay.context.delete({
|
|
9907
|
+
id: record2.contextId,
|
|
9908
|
+
name: record2.contextName
|
|
9909
|
+
});
|
|
9910
|
+
if (!result.success) throw new Error(result.errorMessage || "AgentBay context deletion failed");
|
|
9911
|
+
}
|
|
9912
|
+
return {
|
|
9913
|
+
sessionDeleted: true,
|
|
9914
|
+
...syncContext ? { contextSynced } : {},
|
|
9915
|
+
...deleteContext ? { contextDeleted: true } : {}
|
|
9916
|
+
};
|
|
9917
|
+
}
|
|
9918
|
+
async function closeAgentBayBrowser(selector, options = {}) {
|
|
9919
|
+
const record2 = findRecord(selector);
|
|
9920
|
+
if (!record2) throw new Error(`AgentBay browser not found: ${selector}`);
|
|
9921
|
+
const agentBay = await createClient(resolveAgentBayApiKey());
|
|
9922
|
+
const released = await releaseAgentBayBrowserResources(record2, agentBay, {
|
|
9923
|
+
...options,
|
|
9924
|
+
persistRecord: (updatedRecord) => writeRecord(
|
|
9925
|
+
keyedConfigFile(AGENTBAY_BROWSERS_SUBDIR, updatedRecord.browserId),
|
|
9926
|
+
updatedRecord
|
|
9927
|
+
)
|
|
9928
|
+
});
|
|
9840
9929
|
const closingOwnHost = record2.pid === process.pid;
|
|
9841
9930
|
if (!closingOwnHost) await stopProcess(record2.pid, `--browser-id ${record2.browserId}`);
|
|
9842
9931
|
removeRecord(keyedConfigFile(AGENTBAY_BROWSERS_SUBDIR, record2.browserId));
|
|
@@ -9849,7 +9938,8 @@ async function closeAgentBayBrowser(selector) {
|
|
|
9849
9938
|
browserId: record2.browserId,
|
|
9850
9939
|
provider: "agentbay",
|
|
9851
9940
|
closed: true,
|
|
9852
|
-
|
|
9941
|
+
...released,
|
|
9942
|
+
...record2.persistent === true ? { profileDeleted: options.deleteProfile === true } : { profileDeleted: true }
|
|
9853
9943
|
};
|
|
9854
9944
|
}
|
|
9855
9945
|
|
|
@@ -10006,6 +10096,8 @@ function mergeBrowserInventory(connected, managed) {
|
|
|
10006
10096
|
..."cdpPort" in managedBrowser ? { cdpPort: managedBrowser.cdpPort } : {},
|
|
10007
10097
|
..."agentbaySessionId" in managedBrowser ? { agentbaySessionId: managedBrowser.agentbaySessionId } : {},
|
|
10008
10098
|
..."agentbayImageId" in managedBrowser && managedBrowser.agentbayImageId ? { agentbayImageId: managedBrowser.agentbayImageId } : {},
|
|
10099
|
+
..."agentbayContextId" in managedBrowser && managedBrowser.agentbayContextId ? { agentbayContextId: managedBrowser.agentbayContextId } : {},
|
|
10100
|
+
..."agentbayContextName" in managedBrowser && managedBrowser.agentbayContextName ? { agentbayContextName: managedBrowser.agentbayContextName } : {},
|
|
10009
10101
|
..."agentbayAccessUrl" in managedBrowser && managedBrowser.agentbayAccessUrl ? { agentbayAccessUrl: managedBrowser.agentbayAccessUrl } : {},
|
|
10010
10102
|
createdAt: managedBrowser.createdAt,
|
|
10011
10103
|
..."account" in managedBrowser ? { account: managedBrowser.account } : {},
|
|
@@ -10023,6 +10115,8 @@ function mergeBrowserInventory(connected, managed) {
|
|
|
10023
10115
|
..."cdpPort" in browser ? { cdpPort: browser.cdpPort } : {},
|
|
10024
10116
|
..."agentbaySessionId" in browser ? { agentbaySessionId: browser.agentbaySessionId } : {},
|
|
10025
10117
|
..."agentbayImageId" in browser && browser.agentbayImageId ? { agentbayImageId: browser.agentbayImageId } : {},
|
|
10118
|
+
..."agentbayContextId" in browser && browser.agentbayContextId ? { agentbayContextId: browser.agentbayContextId } : {},
|
|
10119
|
+
..."agentbayContextName" in browser && browser.agentbayContextName ? { agentbayContextName: browser.agentbayContextName } : {},
|
|
10026
10120
|
..."agentbayAccessUrl" in browser && browser.agentbayAccessUrl ? { agentbayAccessUrl: browser.agentbayAccessUrl } : {},
|
|
10027
10121
|
createdAt: browser.createdAt,
|
|
10028
10122
|
..."account" in browser ? { account: browser.account } : {},
|
|
@@ -10047,7 +10141,7 @@ import os2 from "node:os";
|
|
|
10047
10141
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
10048
10142
|
|
|
10049
10143
|
// src/version.ts
|
|
10050
|
-
var NATIVE_HOST_VERSION = true ? "2.5.
|
|
10144
|
+
var NATIVE_HOST_VERSION = true ? "2.5.1" : "unknown";
|
|
10051
10145
|
|
|
10052
10146
|
// src/analytics.ts
|
|
10053
10147
|
var MEASUREMENT_ID = "G-W84LJDZ6PH";
|
|
@@ -31037,7 +31131,7 @@ async function handleSocketLine(socket, line) {
|
|
|
31037
31131
|
`Managed browser name is ambiguous: ${selector}. Use the full browserId from browser_list.`
|
|
31038
31132
|
);
|
|
31039
31133
|
}
|
|
31040
|
-
const result = agentBayExists ? await closeAgentBayBrowser(selector) : await closeManagedBrowser(selector, { deleteProfile: data?.deleteProfile });
|
|
31134
|
+
const result = agentBayExists ? await closeAgentBayBrowser(selector, { deleteProfile: data?.deleteProfile }) : await closeManagedBrowser(selector, { deleteProfile: data?.deleteProfile });
|
|
31041
31135
|
socket.write(JSON.stringify({ id, success: true, data: result }) + "\n");
|
|
31042
31136
|
} catch (error48) {
|
|
31043
31137
|
socket.write(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mearl/native-host",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.1",
|
|
4
4
|
"description": "Native Messaging Host for Mearl — bridges Chrome Extension and local socket server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/install.js",
|
|
@@ -37,9 +37,9 @@
|
|
|
37
37
|
"@types/ws": "^8.18.1",
|
|
38
38
|
"esbuild": "^0.25.2",
|
|
39
39
|
"typescript": "^5.8.3",
|
|
40
|
-
"@mearl/browser-core": "2.5.
|
|
41
|
-
"@mearl/daemon-core": "2.5.
|
|
42
|
-
"@mearl/setup": "2.5.
|
|
40
|
+
"@mearl/browser-core": "2.5.1",
|
|
41
|
+
"@mearl/daemon-core": "2.5.1",
|
|
42
|
+
"@mearl/setup": "2.5.1"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
|
45
45
|
"build": "rm -rf dist/ && node build.mjs",
|