@mearl/client 2.18.0 → 2.19.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/README.md +38 -9
- package/dist/autoUpdate.d.ts +33 -0
- package/dist/autoUpdate.js +359 -0
- package/dist/autoUpdateWorker.d.ts +1 -0
- package/dist/autoUpdateWorker.js +5 -0
- package/dist/bin.js +3 -0
- package/dist/check.d.ts +11 -0
- package/dist/check.js +106 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +8 -1
- package/dist/commands.d.ts +31 -5
- package/dist/commands.js +68 -13
- package/dist/generated-browser-action-protocol.d.ts +27 -9
- package/dist/generated-browser-action-protocol.js +12 -0
- package/dist/index.d.ts +7 -6
- package/dist/index.js +9 -6
- package/dist/officialPluginCatalog.d.ts +5 -1
- package/dist/officialPluginCatalog.js +5 -1
- package/dist/pluginPageBundle.js +265 -5
- package/dist/unifiedConfig.d.ts +2 -0
- package/dist/unifiedConfig.js +23 -0
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -11,14 +11,14 @@ export { APP_PROFILE_NAMES, BROWSER_DEVICE_PRESET_NAMES, BROWSER_ACTIONS, BROWSE
|
|
|
11
11
|
export type { ActionStep, AppProfileName, BrowserAction, BrowserActionMap, BrowserActionRequest, BrowserActionResponse, BrowserCapabilities, BrowserCapabilityAction, BrowserCloseParams, BrowserCommandAction, BrowserInfo, BrowserInfoBase, BrowserJsonValue, BrowserLaunchParams, BrowserProviderOperation, BrowserListResult, BrowserPairingInfo, BrowserReleaseFailure, BrowserReleaseResult, BrowserProviderDefinition, BrowserProviderIdentity, BrowserProviderInputSchema, BrowserProviderListResult, BrowserReference, BrowserDetails, BrowserSource, BrowserStatus, BrowserScreenshotKind, BrowserTransport, CaptureCheckpointParams, CaptureCheckpointResult, BrowserDevicePresetName, BrowserEmulationOptions, ExtensionBrowserAction, GetCookieParams, GetCookieResult, GetEventsParams, GetLogsParams, GetMocksParams, GetRequestsParams, ManagedBrowserInfo, PageClickParams, PageDragEndpoint, PageDragParams, PageDragPoint, PageActAction, PageDiagnosticsOptions, PageDiagnosticsSetting, PageEvalParams, PageFramesParams, PageHoverParams, PageInspectFilter, PageInspectParams, PageNavigateParams, PageObservationWaitOptions, PagePressParams, PageScreenshotParams, PageScrollParams, PageSnapshotParams, PageSnapshotQuery, PageTypeParams, PageUploadParams, PageWaitParams, RegularBrowserInfo, RequestDomainPermissionParams, RulesResult, RunActionName, RunActionsParams, SelectBrowserParams, SelectBrowserResult, SendRequestFile, SendRequestFormValue, SendMtopRequestParams, SendRequestParams, SetAppProfileParams, SetCookieParams, SetCookieResult, SetDeviceEmulationParams, SetMockParams, SetRuleParams, SetTimezoneParams, SetTimezoneResult, TabCloseParams, TabOpenParams, } from './generated-browser-action-protocol.js';
|
|
12
12
|
import { type UnifiedInvokeOptions } from './unified.js';
|
|
13
13
|
import type * as Protocol from './generated-browser-action-protocol.js';
|
|
14
|
-
export declare function tabCheckpoint(params
|
|
14
|
+
export declare function tabCheckpoint(params: Protocol.CaptureCheckpointParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'tab_checkpoint'>>;
|
|
15
15
|
/** Compatibility wrapper for tabCheckpoint. */
|
|
16
|
-
export declare function captureCheckpoint(params
|
|
17
|
-
export declare function getRequests(params
|
|
18
|
-
export declare function getLogs(params
|
|
19
|
-
export declare function getEvents(params
|
|
16
|
+
export declare function captureCheckpoint(params: Protocol.CaptureCheckpointParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'tab_checkpoint'>>;
|
|
17
|
+
export declare function getRequests(params: Protocol.GetRequestsParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'get_requests'>>;
|
|
18
|
+
export declare function getLogs(params: Protocol.GetLogsParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'get_logs'>>;
|
|
19
|
+
export declare function getEvents(params: Protocol.GetEventsParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'get_events'>>;
|
|
20
20
|
export declare function setMock(params: Protocol.SetMockParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'set_mock'>>;
|
|
21
|
-
export declare function getMocks(params
|
|
21
|
+
export declare function getMocks(params: Protocol.GetMocksParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'get_mocks'>>;
|
|
22
22
|
export declare function sendRequest(params: Protocol.SendRequestParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'send_request'>>;
|
|
23
23
|
export declare function sendMtopRequest(params: Protocol.SendMtopRequestParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'send_mtop_request'>>;
|
|
24
24
|
export declare function browserList(options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'browser_list'>>;
|
|
@@ -32,6 +32,7 @@ export declare function pageScreenshot(params: Protocol.PageScreenshotParams, op
|
|
|
32
32
|
export declare function tabOpen(params: Protocol.TabOpenParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'tab_open'>>;
|
|
33
33
|
export declare function tabClose(params: Protocol.TabCloseParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'tab_close'>>;
|
|
34
34
|
export declare function tabList(options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'tab_list'>>;
|
|
35
|
+
export declare function tabGroup(params: Protocol.TabGroupParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'tab_group'>>;
|
|
35
36
|
export declare function pageClick(params: Protocol.PageClickParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'page_click'>>;
|
|
36
37
|
export declare function pageDrag(params: Protocol.PageDragParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'page_drag'>>;
|
|
37
38
|
export declare function pageType(params: Protocol.PageTypeParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'page_type'>>;
|
package/dist/index.js
CHANGED
|
@@ -7,26 +7,26 @@
|
|
|
7
7
|
export { UnifiedClient, UnifiedClient as MearlClient, decodeBrowserTarget, invoke, invokePlugin, listCloudConnectors, } from './unified.js';
|
|
8
8
|
export { APP_PROFILE_NAMES, BROWSER_DEVICE_PRESET_NAMES, BROWSER_ACTIONS, BROWSER_COMMAND_ACTIONS, EXTENSION_BROWSER_ACTIONS, PAGE_ACT_ACTIONS, SEND_REQUEST_MAX_FILES, SEND_REQUEST_MAX_TOTAL_BASE64_FILE_BYTES, SEND_REQUEST_MAX_TOTAL_FILE_BYTES, isBrowserAction, isBrowserCapabilityAction, isBrowserCommandAction, isExtensionBrowserAction, } from './generated-browser-action-protocol.js';
|
|
9
9
|
import { invoke } from './unified.js';
|
|
10
|
-
export function tabCheckpoint(params
|
|
10
|
+
export function tabCheckpoint(params, options) {
|
|
11
11
|
return invoke('tab_checkpoint', params, options);
|
|
12
12
|
}
|
|
13
13
|
/** Compatibility wrapper for tabCheckpoint. */
|
|
14
|
-
export function captureCheckpoint(params
|
|
14
|
+
export function captureCheckpoint(params, options) {
|
|
15
15
|
return tabCheckpoint(params, options);
|
|
16
16
|
}
|
|
17
|
-
export function getRequests(params
|
|
17
|
+
export function getRequests(params, options) {
|
|
18
18
|
return invoke('get_requests', params, options);
|
|
19
19
|
}
|
|
20
|
-
export function getLogs(params
|
|
20
|
+
export function getLogs(params, options) {
|
|
21
21
|
return invoke('get_logs', params, options);
|
|
22
22
|
}
|
|
23
|
-
export function getEvents(params
|
|
23
|
+
export function getEvents(params, options) {
|
|
24
24
|
return invoke('get_events', params, options);
|
|
25
25
|
}
|
|
26
26
|
export function setMock(params, options) {
|
|
27
27
|
return invoke('set_mock', params, options);
|
|
28
28
|
}
|
|
29
|
-
export function getMocks(params
|
|
29
|
+
export function getMocks(params, options) {
|
|
30
30
|
return invoke('get_mocks', params, options);
|
|
31
31
|
}
|
|
32
32
|
export function sendRequest(params, options) {
|
|
@@ -68,6 +68,9 @@ export function tabClose(params, options) {
|
|
|
68
68
|
export function tabList(options) {
|
|
69
69
|
return invoke('tab_list', {}, options);
|
|
70
70
|
}
|
|
71
|
+
export function tabGroup(params, options) {
|
|
72
|
+
return invoke('tab_group', params, options);
|
|
73
|
+
}
|
|
71
74
|
export function pageClick(params, options) {
|
|
72
75
|
return invoke('page_click', params, options);
|
|
73
76
|
}
|
|
@@ -9,9 +9,13 @@ export declare const OFFICIAL_PLUGINS: {
|
|
|
9
9
|
readonly buc: {
|
|
10
10
|
readonly description: "使用 BUC 身份请求内部服务";
|
|
11
11
|
readonly installArgs: readonly ["trip/mearl", "--skill", "buc-request", "--yes"];
|
|
12
|
-
readonly setup: "alibaba";
|
|
13
12
|
readonly skill: "buc-request";
|
|
14
13
|
};
|
|
14
|
+
readonly authx: {
|
|
15
|
+
readonly description: "使用 AuthX 身份请求内部服务";
|
|
16
|
+
readonly installArgs: readonly ["trip/mearl", "--skill", "authx-request", "--yes"];
|
|
17
|
+
readonly skill: "authx-request";
|
|
18
|
+
};
|
|
15
19
|
readonly tdbank: {
|
|
16
20
|
readonly description: "查询、借用和切换 TDBank 测试账号";
|
|
17
21
|
readonly installArgs: readonly ["trip/mearl", "--skill", "tdbank-account", "--yes"];
|
|
@@ -3,9 +3,13 @@ export const OFFICIAL_PLUGINS = {
|
|
|
3
3
|
buc: {
|
|
4
4
|
description: '使用 BUC 身份请求内部服务',
|
|
5
5
|
installArgs: ['trip/mearl', '--skill', 'buc-request', '--yes'],
|
|
6
|
-
setup: 'alibaba',
|
|
7
6
|
skill: 'buc-request',
|
|
8
7
|
},
|
|
8
|
+
authx: {
|
|
9
|
+
description: '使用 AuthX 身份请求内部服务',
|
|
10
|
+
installArgs: ['trip/mearl', '--skill', 'authx-request', '--yes'],
|
|
11
|
+
skill: 'authx-request',
|
|
12
|
+
},
|
|
9
13
|
tdbank: {
|
|
10
14
|
description: '查询、借用和切换 TDBank 测试账号',
|
|
11
15
|
installArgs: ['trip/mearl', '--skill', 'tdbank-account', '--yes'],
|
package/dist/pluginPageBundle.js
CHANGED
|
@@ -84,6 +84,32 @@ const PAGE_BRIDGE_SCRIPT = String.raw `(() => {
|
|
|
84
84
|
await requestHost('clipboard-write', { text });
|
|
85
85
|
};
|
|
86
86
|
|
|
87
|
+
const openExternalLink = async url => {
|
|
88
|
+
if (typeof url !== 'string' || !url || url.length > 8192) {
|
|
89
|
+
throw new Error('External link must be a non-empty URL no longer than 8192 characters');
|
|
90
|
+
}
|
|
91
|
+
await requestHost('open-external-link', { url });
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const handleExternalLinkClick = event => {
|
|
95
|
+
if (event.defaultPrevented || event.button !== 0) return;
|
|
96
|
+
const link = event.target?.closest?.('a[href]');
|
|
97
|
+
if (!link || String(link.target).toLowerCase() !== '_blank' || link.hasAttribute?.('download')) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
let url;
|
|
101
|
+
try {
|
|
102
|
+
url = new URL(link.href);
|
|
103
|
+
} catch {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:') return;
|
|
107
|
+
event.preventDefault();
|
|
108
|
+
void openExternalLink(url.href).catch(error => {
|
|
109
|
+
console.error('Failed to open external link', error);
|
|
110
|
+
});
|
|
111
|
+
};
|
|
112
|
+
|
|
87
113
|
const toast = async (message, options = {}) => {
|
|
88
114
|
if (typeof message !== 'string' || !message.trim() || message.length > 4000) {
|
|
89
115
|
throw new Error('Toast message must be a non-empty string no longer than 4000 characters');
|
|
@@ -106,16 +132,213 @@ const PAGE_BRIDGE_SCRIPT = String.raw `(() => {
|
|
|
106
132
|
throw new Error('Agent panel options must be an object');
|
|
107
133
|
}
|
|
108
134
|
const layout = options.layout;
|
|
109
|
-
if (layout !== undefined && layout !== 'drawer' && layout !== 'workspace') {
|
|
110
|
-
throw new Error('Agent panel layout must be drawer or
|
|
135
|
+
if (layout !== undefined && layout !== 'drawer' && layout !== 'workspace' && layout !== 'inline') {
|
|
136
|
+
throw new Error('Agent panel layout must be drawer, workspace, or inline');
|
|
111
137
|
}
|
|
112
138
|
return layout;
|
|
113
139
|
};
|
|
114
140
|
|
|
141
|
+
const agentPanelKey = (options, required = false) => {
|
|
142
|
+
const key = typeof options.key === 'string' ? options.key.trim() : '';
|
|
143
|
+
if ((required || options.key !== undefined) && (!key || key.length > 128)) {
|
|
144
|
+
throw new Error('Agent panel key must be a non-empty string no longer than 128 characters');
|
|
145
|
+
}
|
|
146
|
+
return key || null;
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const agentPanelCwd = options => {
|
|
150
|
+
const cwd = options.cwd;
|
|
151
|
+
if (
|
|
152
|
+
cwd !== undefined &&
|
|
153
|
+
(typeof cwd !== 'string' ||
|
|
154
|
+
!cwd.trim() ||
|
|
155
|
+
cwd.length > 4096 ||
|
|
156
|
+
!/^(?:\/|[a-zA-Z]:[\\/])/.test(cwd.trim()))
|
|
157
|
+
) {
|
|
158
|
+
throw new Error('Agent panel cwd must be an absolute path no longer than 4096 characters');
|
|
159
|
+
}
|
|
160
|
+
return cwd === undefined ? null : cwd.trim();
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const agentPanelContext = options => {
|
|
164
|
+
const context = options.context;
|
|
165
|
+
if (
|
|
166
|
+
context !== undefined &&
|
|
167
|
+
(typeof context !== 'string' || !context.trim() || context.length > 65536)
|
|
168
|
+
) {
|
|
169
|
+
throw new Error('Agent panel context must be a non-empty string no longer than 65536 characters');
|
|
170
|
+
}
|
|
171
|
+
return context === undefined ? null : context.trim();
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const inlineAgentPanels = new Map();
|
|
175
|
+
|
|
176
|
+
const stopInlineAgentPanelTracking = key => {
|
|
177
|
+
if (key) {
|
|
178
|
+
inlineAgentPanels.get(key)?.cleanup();
|
|
179
|
+
inlineAgentPanels.delete(key);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
for (const tracked of inlineAgentPanels.values()) tracked.cleanup();
|
|
183
|
+
inlineAgentPanels.clear();
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const inlineAgentPanelAnchor = (options, key) => {
|
|
187
|
+
const anchor = options.anchor;
|
|
188
|
+
if (!(anchor instanceof Element)) {
|
|
189
|
+
throw new Error('Inline Agent panel anchor must be an element');
|
|
190
|
+
}
|
|
191
|
+
const rect = anchor.getBoundingClientRect();
|
|
192
|
+
if (![rect.top, rect.left, rect.width, rect.height].every(Number.isFinite)) {
|
|
193
|
+
throw new Error('Inline Agent panel anchor returned invalid bounds');
|
|
194
|
+
}
|
|
195
|
+
return {
|
|
196
|
+
element: anchor,
|
|
197
|
+
key,
|
|
198
|
+
bounds: { top: rect.top, left: rect.left, width: rect.width, height: rect.height },
|
|
199
|
+
};
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const trackInlineAgentPanel = presentation => {
|
|
203
|
+
stopInlineAgentPanelTracking(presentation.key);
|
|
204
|
+
let frame = null;
|
|
205
|
+
const update = () => {
|
|
206
|
+
frame = null;
|
|
207
|
+
if (!presentation.element.isConnected || !port) return;
|
|
208
|
+
const rect = presentation.element.getBoundingClientRect();
|
|
209
|
+
if (![rect.top, rect.left, rect.width, rect.height].every(Number.isFinite)) return;
|
|
210
|
+
const bounds = { top: rect.top, left: rect.left, width: rect.width, height: rect.height };
|
|
211
|
+
if (
|
|
212
|
+
bounds.top === presentation.bounds.top &&
|
|
213
|
+
bounds.left === presentation.bounds.left &&
|
|
214
|
+
bounds.width === presentation.bounds.width &&
|
|
215
|
+
bounds.height === presentation.bounds.height
|
|
216
|
+
) return;
|
|
217
|
+
presentation.bounds = bounds;
|
|
218
|
+
port.postMessage({
|
|
219
|
+
type: 'agent-panel-position',
|
|
220
|
+
key: presentation.key,
|
|
221
|
+
bounds,
|
|
222
|
+
});
|
|
223
|
+
};
|
|
224
|
+
const schedule = () => {
|
|
225
|
+
if (frame !== null) return;
|
|
226
|
+
frame = requestAnimationFrame(update);
|
|
227
|
+
};
|
|
228
|
+
const observer = typeof ResizeObserver === 'function' ? new ResizeObserver(schedule) : null;
|
|
229
|
+
observer?.observe(presentation.element);
|
|
230
|
+
observer?.observe(document.documentElement);
|
|
231
|
+
const mutationObserver = typeof MutationObserver === 'function'
|
|
232
|
+
? new MutationObserver(schedule)
|
|
233
|
+
: null;
|
|
234
|
+
mutationObserver?.observe(document.documentElement, {
|
|
235
|
+
attributes: true,
|
|
236
|
+
childList: true,
|
|
237
|
+
characterData: true,
|
|
238
|
+
subtree: true,
|
|
239
|
+
});
|
|
240
|
+
window.addEventListener('resize', schedule);
|
|
241
|
+
document.addEventListener('scroll', schedule, true);
|
|
242
|
+
const cleanup = () => {
|
|
243
|
+
if (frame !== null) cancelAnimationFrame(frame);
|
|
244
|
+
observer?.disconnect();
|
|
245
|
+
mutationObserver?.disconnect();
|
|
246
|
+
window.removeEventListener('resize', schedule);
|
|
247
|
+
document.removeEventListener('scroll', schedule, true);
|
|
248
|
+
};
|
|
249
|
+
inlineAgentPanels.set(presentation.key, { presentation, cleanup });
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
const scrollInlineAgentPage = (presentation, deltaX, deltaY) => {
|
|
253
|
+
const scrollAxis = (axis, delta) => {
|
|
254
|
+
if (!delta) return;
|
|
255
|
+
let element = presentation.element;
|
|
256
|
+
while (element) {
|
|
257
|
+
const style = window.getComputedStyle(element);
|
|
258
|
+
const overflow = axis === 'x' ? style.overflowX : style.overflowY;
|
|
259
|
+
const scrollSize = axis === 'x' ? element.scrollWidth : element.scrollHeight;
|
|
260
|
+
const clientSize = axis === 'x' ? element.clientWidth : element.clientHeight;
|
|
261
|
+
if (/^(auto|scroll|overlay)$/.test(overflow) && scrollSize > clientSize) {
|
|
262
|
+
const scrollPosition = axis === 'x' ? element.scrollLeft : element.scrollTop;
|
|
263
|
+
const maximum = scrollSize - clientSize;
|
|
264
|
+
if ((delta < 0 && scrollPosition > 0) || (delta > 0 && scrollPosition < maximum - 1)) {
|
|
265
|
+
if (axis === 'x') element.scrollLeft += delta;
|
|
266
|
+
else element.scrollTop += delta;
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
element = element.parentElement;
|
|
271
|
+
}
|
|
272
|
+
window.scrollBy(axis === 'x' ? delta : 0, axis === 'y' ? delta : 0);
|
|
273
|
+
};
|
|
274
|
+
scrollAxis('x', deltaX);
|
|
275
|
+
scrollAxis('y', deltaY);
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
const agentPanelPresentation = (options, layout, key) => {
|
|
279
|
+
if (layout !== 'inline') return null;
|
|
280
|
+
return inlineAgentPanelAnchor(options, key);
|
|
281
|
+
};
|
|
282
|
+
|
|
115
283
|
const setAgentPanelVisible = async (visible, options = {}) => {
|
|
116
284
|
if (typeof visible !== 'boolean') throw new Error('Agent panel visibility must be a boolean');
|
|
117
285
|
const layout = agentPanelLayout(options);
|
|
118
|
-
|
|
286
|
+
const key = agentPanelKey(options, visible && layout === 'inline');
|
|
287
|
+
const cwd = visible ? agentPanelCwd(options) : null;
|
|
288
|
+
const context = visible ? agentPanelContext(options) : null;
|
|
289
|
+
const presentation = visible ? agentPanelPresentation(options, layout, key) : null;
|
|
290
|
+
const request = requestHost('agent-panel', {
|
|
291
|
+
visible,
|
|
292
|
+
...(layout ? { layout } : {}),
|
|
293
|
+
...(key ? { key } : {}),
|
|
294
|
+
...(cwd ? { cwd } : {}),
|
|
295
|
+
...(context ? { context } : {}),
|
|
296
|
+
...(presentation ? { bounds: presentation.bounds } : {}),
|
|
297
|
+
});
|
|
298
|
+
if (presentation) {
|
|
299
|
+
await ready;
|
|
300
|
+
trackInlineAgentPanel(presentation);
|
|
301
|
+
} else if (!visible && key) {
|
|
302
|
+
stopInlineAgentPanelTracking(key);
|
|
303
|
+
} else {
|
|
304
|
+
stopInlineAgentPanelTracking();
|
|
305
|
+
}
|
|
306
|
+
try {
|
|
307
|
+
await request;
|
|
308
|
+
} catch (error) {
|
|
309
|
+
if (presentation) stopInlineAgentPanelTracking(presentation.key);
|
|
310
|
+
throw error;
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
const agentGuideText = (value, label, maximumLength) => {
|
|
315
|
+
const normalized = typeof value === 'string' ? value.trim() : '';
|
|
316
|
+
if (!normalized || normalized.length > maximumLength) {
|
|
317
|
+
throw new Error(label + ' must be a non-empty string no longer than ' + maximumLength + ' characters');
|
|
318
|
+
}
|
|
319
|
+
return normalized;
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
const setAgentGuides = async guides => {
|
|
323
|
+
if (!Array.isArray(guides) || guides.length === 0 || guides.length > 6) {
|
|
324
|
+
throw new Error('Agent guides must contain between 1 and 6 items');
|
|
325
|
+
}
|
|
326
|
+
const normalized = guides.map((guide, index) => {
|
|
327
|
+
if (!guide || typeof guide !== 'object' || Array.isArray(guide)) {
|
|
328
|
+
throw new Error('Agent guide ' + index + ' must be an object');
|
|
329
|
+
}
|
|
330
|
+
const icon = guide.icon === undefined ? undefined : agentGuideText(guide.icon, 'Agent guide icon', 40);
|
|
331
|
+
if (icon && !/^[a-z][a-z0-9-]*$/.test(icon)) {
|
|
332
|
+
throw new Error('Agent guide icon must use kebab-case');
|
|
333
|
+
}
|
|
334
|
+
return {
|
|
335
|
+
title: agentGuideText(guide.title, 'Agent guide title', 80),
|
|
336
|
+
description: agentGuideText(guide.description, 'Agent guide description', 160),
|
|
337
|
+
prompt: agentGuideText(guide.prompt, 'Agent guide prompt', 4000),
|
|
338
|
+
...(icon ? { icon } : {}),
|
|
339
|
+
};
|
|
340
|
+
});
|
|
341
|
+
await requestHost('agent-guides', { guides: normalized });
|
|
119
342
|
};
|
|
120
343
|
|
|
121
344
|
const runAgentTask = async (prompt, options = {}) => {
|
|
@@ -126,7 +349,13 @@ const PAGE_BRIDGE_SCRIPT = String.raw `(() => {
|
|
|
126
349
|
throw new Error('Agent task options must be an object');
|
|
127
350
|
}
|
|
128
351
|
const cwd = options.cwd;
|
|
352
|
+
const ephemeral = options.ephemeral;
|
|
129
353
|
const layout = agentPanelLayout(options);
|
|
354
|
+
const key = agentPanelKey(options, layout === 'inline');
|
|
355
|
+
const presentation = agentPanelPresentation(options, layout, key);
|
|
356
|
+
if (ephemeral !== undefined && ephemeral !== false) {
|
|
357
|
+
throw new Error('Temporary Agent conversations are not supported');
|
|
358
|
+
}
|
|
130
359
|
if (
|
|
131
360
|
cwd !== undefined &&
|
|
132
361
|
(typeof cwd !== 'string' ||
|
|
@@ -136,11 +365,25 @@ const PAGE_BRIDGE_SCRIPT = String.raw `(() => {
|
|
|
136
365
|
) {
|
|
137
366
|
throw new Error('Agent task cwd must be an absolute path no longer than 4096 characters');
|
|
138
367
|
}
|
|
139
|
-
|
|
368
|
+
const request = requestHost('agent-task', {
|
|
140
369
|
prompt: prompt.trim(),
|
|
141
370
|
...(cwd !== undefined ? { cwd: cwd.trim() } : {}),
|
|
142
371
|
...(layout ? { layout } : {}),
|
|
372
|
+
...(key ? { key } : {}),
|
|
373
|
+
...(presentation ? { bounds: presentation.bounds } : {}),
|
|
143
374
|
});
|
|
375
|
+
if (presentation) {
|
|
376
|
+
await ready;
|
|
377
|
+
trackInlineAgentPanel(presentation);
|
|
378
|
+
} else {
|
|
379
|
+
stopInlineAgentPanelTracking();
|
|
380
|
+
}
|
|
381
|
+
try {
|
|
382
|
+
await request;
|
|
383
|
+
} catch (error) {
|
|
384
|
+
if (presentation) stopInlineAgentPanelTracking(presentation.key);
|
|
385
|
+
throw error;
|
|
386
|
+
}
|
|
144
387
|
};
|
|
145
388
|
|
|
146
389
|
const setQueryParam = async (name, value) => {
|
|
@@ -155,7 +398,7 @@ const PAGE_BRIDGE_SCRIPT = String.raw `(() => {
|
|
|
155
398
|
return query;
|
|
156
399
|
};
|
|
157
400
|
|
|
158
|
-
const api = { copyText, invoke, operation, ready: () => ready, runAgentTask, runningOperations, selectDirectory, setAgentPanelVisible, setQueryParam, start, toast };
|
|
401
|
+
const api = { copyText, invoke, operation, ready: () => ready, runAgentTask, runningOperations, selectDirectory, setAgentGuides, setAgentPanelVisible, setQueryParam, start, toast };
|
|
159
402
|
const ui = globalThis.__mearlToolboxUi;
|
|
160
403
|
if (ui !== undefined) {
|
|
161
404
|
if (!ui || typeof ui !== 'object' || ui.runtime !== 'preact') {
|
|
@@ -166,6 +409,7 @@ const PAGE_BRIDGE_SCRIPT = String.raw `(() => {
|
|
|
166
409
|
}
|
|
167
410
|
Object.defineProperty(api, 'context', { enumerable: true, get: () => context });
|
|
168
411
|
Object.defineProperty(window, 'mearl', { configurable: false, value: Object.freeze(api) });
|
|
412
|
+
document.addEventListener('click', handleExternalLinkClick);
|
|
169
413
|
|
|
170
414
|
const applyContext = nextContext => {
|
|
171
415
|
const theme =
|
|
@@ -198,6 +442,22 @@ const PAGE_BRIDGE_SCRIPT = String.raw `(() => {
|
|
|
198
442
|
applyContext(response.context);
|
|
199
443
|
return;
|
|
200
444
|
}
|
|
445
|
+
if (
|
|
446
|
+
response?.type === 'agent-panel-wheel' &&
|
|
447
|
+
typeof response.key === 'string' &&
|
|
448
|
+
inlineAgentPanels.has(response.key) &&
|
|
449
|
+
typeof response.deltaX === 'number' &&
|
|
450
|
+
Number.isFinite(response.deltaX) &&
|
|
451
|
+
typeof response.deltaY === 'number' &&
|
|
452
|
+
Number.isFinite(response.deltaY)
|
|
453
|
+
) {
|
|
454
|
+
scrollInlineAgentPage(
|
|
455
|
+
inlineAgentPanels.get(response.key).presentation,
|
|
456
|
+
response.deltaX,
|
|
457
|
+
response.deltaY,
|
|
458
|
+
);
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
201
461
|
if (response?.type !== 'result' || typeof response.requestId !== 'string') return;
|
|
202
462
|
const request = pending.get(response.requestId);
|
|
203
463
|
if (!request) return;
|
package/dist/unifiedConfig.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export interface CloudServerConfig {
|
|
2
2
|
server: string;
|
|
3
3
|
}
|
|
4
|
+
/** Number of local calendar days between CLI update checks; null disables them. */
|
|
5
|
+
export declare function loadCliAutoUpdateIntervalDays(configPath?: string): number | null;
|
|
4
6
|
export declare function getCloudServerConfigPath(): string;
|
|
5
7
|
export declare function loadCloudServerConfig(): CloudServerConfig | null;
|
|
6
8
|
export declare function loadLocalConnectorId(): string | null;
|
package/dist/unifiedConfig.js
CHANGED
|
@@ -2,6 +2,29 @@ import { existsSync, readFileSync } from 'node:fs';
|
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
const MEARL_CONFIG_DIR = join(homedir(), '.mearl');
|
|
5
|
+
/** Number of local calendar days between CLI update checks; null disables them. */
|
|
6
|
+
export function loadCliAutoUpdateIntervalDays(configPath = join(MEARL_CONFIG_DIR, 'config.json')) {
|
|
7
|
+
try {
|
|
8
|
+
const config = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
9
|
+
if (config.cliAutoUpdate === false)
|
|
10
|
+
return null;
|
|
11
|
+
if (config.cliAutoUpdate === undefined)
|
|
12
|
+
return 1;
|
|
13
|
+
if (typeof config.cliAutoUpdate === 'object' &&
|
|
14
|
+
config.cliAutoUpdate !== null &&
|
|
15
|
+
!Array.isArray(config.cliAutoUpdate)) {
|
|
16
|
+
const { intervalDays } = config.cliAutoUpdate;
|
|
17
|
+
if (typeof intervalDays === 'number' &&
|
|
18
|
+
Number.isSafeInteger(intervalDays) &&
|
|
19
|
+
intervalDays > 0)
|
|
20
|
+
return intervalDays;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// A missing or invalid config uses the daily default.
|
|
25
|
+
}
|
|
26
|
+
return 1;
|
|
27
|
+
}
|
|
5
28
|
export function getCloudServerConfigPath() {
|
|
6
29
|
return join(MEARL_CONFIG_DIR, 'cloud-server.json');
|
|
7
30
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mearl/client",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.19.1",
|
|
4
4
|
"description": "Unified Mearl SDK & CLI for local and remote browsers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -59,8 +59,8 @@
|
|
|
59
59
|
"commander": "^15.0.0",
|
|
60
60
|
"fastest-levenshtein": "^1.0.16",
|
|
61
61
|
"ws": "^8.18.0",
|
|
62
|
-
"@mearl/cloud-types": "2.
|
|
63
|
-
"@mearl/provider": "2.
|
|
62
|
+
"@mearl/cloud-types": "2.19.1",
|
|
63
|
+
"@mearl/provider": "2.19.1"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
66
|
"@types/node": "^24.9.1",
|