@quanta-intellect/vessel-browser 0.1.81 → 0.1.84
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 +2 -5
- package/out/main/index.js +173 -11
- package/out/preload/index.js +2 -0
- package/out/renderer/assets/{index-DOJa9vgV.js → index-DRzS5XLW.js} +254 -193
- package/out/renderer/index.html +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<div align="center">
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|

|
|
4
4
|
|
|
5
5
|
<a href="https://snapcraft.io/vessel-browser">
|
|
@@ -22,11 +22,9 @@ Vessel gives external agent harnesses a real browser with durable state, MCP con
|
|
|
22
22
|
*Vessel is in active development and currently makes no security assurances. Use and deploy it with care.*
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
|
|
26
25
|
https://github.com/user-attachments/assets/0a72b48a-873a-4eb0-b8f2-23e34d8472c4
|
|
27
26
|
|
|
28
27
|
|
|
29
|
-
|
|
30
28
|
## Quick Start
|
|
31
29
|
|
|
32
30
|
Want the full agent toolkit from day one? [Start a 7-Day Free Trial of Vessel Premium — $5.99/mo](https://vesselpremium.quantaintellect.com/checkout).
|
|
@@ -80,7 +78,6 @@ Most browser automation stacks are either headless, stateless, or designed aroun
|
|
|
80
78
|
<img width="1280" height="800" alt="@quanta-intellectvessel-browser_2026-03-17_195754_6624" src="https://github.com/user-attachments/assets/3b3d2033-5a59-4806-bbc1-359efb7b43a9" />
|
|
81
79
|
|
|
82
80
|
|
|
83
|
-
|
|
84
81
|
<img width="1280" height="800" alt="vessel_2026-03-17_145154_5389" src="https://github.com/user-attachments/assets/b1c08d6c-bcdf-4c9a-8429-a71a23a61903" />
|
|
85
82
|
|
|
86
83
|
Vessel is built for persistent web agents that need a real browser, durable state, and a human-visible interface. The agent is the primary operator. The human follows along in the live browser UI, audits what the agent is doing, and steers when needed.
|
|
@@ -420,7 +417,7 @@ mcp_servers:
|
|
|
420
417
|
connect_timeout: 30
|
|
421
418
|
```
|
|
422
419
|
|
|
423
|
-
## Configuration
|
|
420
|
+
## Configuration
|
|
424
421
|
|
|
425
422
|
The installer writes three snippets to:
|
|
426
423
|
|
package/out/main/index.js
CHANGED
|
@@ -183,6 +183,15 @@ function sanitizePort(value) {
|
|
|
183
183
|
});
|
|
184
184
|
return defaults.mcpPort;
|
|
185
185
|
}
|
|
186
|
+
function sanitizeReasoningEffortLevel$1(value) {
|
|
187
|
+
return value === "low" || value === "medium" || value === "high" || value === "max" || value === "off" ? value : "off";
|
|
188
|
+
}
|
|
189
|
+
function sanitizeChatProvider(provider) {
|
|
190
|
+
return provider ? {
|
|
191
|
+
...provider,
|
|
192
|
+
reasoningEffort: sanitizeReasoningEffortLevel$1(provider.reasoningEffort)
|
|
193
|
+
} : null;
|
|
194
|
+
}
|
|
186
195
|
function loadSettings() {
|
|
187
196
|
if (settings) return settings;
|
|
188
197
|
settingsIssues = [];
|
|
@@ -194,7 +203,9 @@ function loadSettings() {
|
|
|
194
203
|
settings = {
|
|
195
204
|
...defaults,
|
|
196
205
|
...parsed,
|
|
197
|
-
chatProvider:
|
|
206
|
+
chatProvider: sanitizeChatProvider(
|
|
207
|
+
mergeChatProviderSecret(parsed.chatProvider ?? null)
|
|
208
|
+
),
|
|
198
209
|
mcpPort: sanitizePort(parsed.mcpPort ?? defaults.mcpPort),
|
|
199
210
|
agentTranscriptMode: parsed.agentTranscriptMode === "off" || parsed.agentTranscriptMode === "summary" || parsed.agentTranscriptMode === "full" ? parsed.agentTranscriptMode : parsed.showAgentTranscript === false ? "off" : defaults.agentTranscriptMode
|
|
200
211
|
};
|
|
@@ -260,7 +271,10 @@ function setSetting(key, value) {
|
|
|
260
271
|
settings.chatProvider = {
|
|
261
272
|
...nextProvider,
|
|
262
273
|
apiKey: resolvedApiKey,
|
|
263
|
-
hasApiKey: Boolean(resolvedApiKey)
|
|
274
|
+
hasApiKey: Boolean(resolvedApiKey),
|
|
275
|
+
reasoningEffort: sanitizeReasoningEffortLevel$1(
|
|
276
|
+
nextProvider.reasoningEffort
|
|
277
|
+
)
|
|
264
278
|
};
|
|
265
279
|
}
|
|
266
280
|
} else {
|
|
@@ -3284,6 +3298,7 @@ const Channels = {
|
|
|
3284
3298
|
FOLDER_CREATE: "bookmarks:folder-create",
|
|
3285
3299
|
FOLDER_REMOVE: "bookmarks:folder-remove",
|
|
3286
3300
|
FOLDER_RENAME: "bookmarks:folder-rename",
|
|
3301
|
+
FOLDER_EXPORT_HTML: "bookmarks:folder-export-html",
|
|
3287
3302
|
// Highlights
|
|
3288
3303
|
HIGHLIGHT_CAPTURE: "highlights:capture",
|
|
3289
3304
|
HIGHLIGHT_CAPTURE_RESULT: "highlights:capture-result",
|
|
@@ -6818,17 +6833,38 @@ function isClickReadLoop(names) {
|
|
|
6818
6833
|
}
|
|
6819
6834
|
return clickReadPairs >= 2;
|
|
6820
6835
|
}
|
|
6836
|
+
const ANTHROPIC_MAX_TOKENS = 4096;
|
|
6821
6837
|
function isRecord(value) {
|
|
6822
6838
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
6823
6839
|
}
|
|
6840
|
+
function anthropicModelLikelySupportsThinking(model) {
|
|
6841
|
+
return /claude-(?:opus|sonnet|haiku)-4/i.test(model.trim());
|
|
6842
|
+
}
|
|
6843
|
+
function toAnthropicThinkingConfig(effort, model) {
|
|
6844
|
+
if (!effort || effort === "off" || !anthropicModelLikelySupportsThinking(model)) {
|
|
6845
|
+
return void 0;
|
|
6846
|
+
}
|
|
6847
|
+
const budgetByEffort = {
|
|
6848
|
+
low: 1024,
|
|
6849
|
+
medium: 2048,
|
|
6850
|
+
high: 3072,
|
|
6851
|
+
max: 3584
|
|
6852
|
+
};
|
|
6853
|
+
return {
|
|
6854
|
+
type: "enabled",
|
|
6855
|
+
budget_tokens: budgetByEffort[effort]
|
|
6856
|
+
};
|
|
6857
|
+
}
|
|
6824
6858
|
class AnthropicProvider {
|
|
6825
6859
|
agentToolProfile = "default";
|
|
6826
6860
|
client;
|
|
6827
6861
|
model;
|
|
6862
|
+
reasoningEffort;
|
|
6828
6863
|
abortController = null;
|
|
6829
|
-
constructor(apiKey, model) {
|
|
6864
|
+
constructor(apiKey, model, reasoningEffort = "off") {
|
|
6830
6865
|
this.client = new Anthropic({ apiKey });
|
|
6831
6866
|
this.model = model || "claude-sonnet-4-20250514";
|
|
6867
|
+
this.reasoningEffort = reasoningEffort;
|
|
6832
6868
|
}
|
|
6833
6869
|
async streamQuery(systemPrompt, userMessage, onChunk, onEnd, history) {
|
|
6834
6870
|
this.abortController = new AbortController();
|
|
@@ -6836,13 +6872,15 @@ class AnthropicProvider {
|
|
|
6836
6872
|
...(history ?? []).map((m) => ({ role: m.role, content: m.content })),
|
|
6837
6873
|
{ role: "user", content: userMessage }
|
|
6838
6874
|
];
|
|
6875
|
+
const thinking = toAnthropicThinkingConfig(this.reasoningEffort, this.model);
|
|
6839
6876
|
try {
|
|
6840
6877
|
const stream = this.client.messages.stream(
|
|
6841
6878
|
{
|
|
6842
6879
|
model: this.model,
|
|
6843
|
-
max_tokens:
|
|
6880
|
+
max_tokens: ANTHROPIC_MAX_TOKENS,
|
|
6844
6881
|
system: systemPrompt,
|
|
6845
|
-
messages
|
|
6882
|
+
messages,
|
|
6883
|
+
...thinking ? { thinking } : {}
|
|
6846
6884
|
},
|
|
6847
6885
|
{ signal: this.abortController.signal }
|
|
6848
6886
|
);
|
|
@@ -6868,6 +6906,7 @@ class AnthropicProvider {
|
|
|
6868
6906
|
...(history ?? []).map((m) => ({ role: m.role, content: m.content })),
|
|
6869
6907
|
{ role: "user", content: userMessage }
|
|
6870
6908
|
];
|
|
6909
|
+
const thinking = toAnthropicThinkingConfig(this.reasoningEffort, this.model);
|
|
6871
6910
|
try {
|
|
6872
6911
|
const maxIterations = getEffectiveMaxIterations();
|
|
6873
6912
|
let iterationsUsed = 0;
|
|
@@ -6878,10 +6917,11 @@ class AnthropicProvider {
|
|
|
6878
6917
|
const stream = this.client.messages.stream(
|
|
6879
6918
|
{
|
|
6880
6919
|
model: this.model,
|
|
6881
|
-
max_tokens:
|
|
6920
|
+
max_tokens: ANTHROPIC_MAX_TOKENS,
|
|
6882
6921
|
system: systemPrompt,
|
|
6883
6922
|
messages,
|
|
6884
|
-
tools
|
|
6923
|
+
tools,
|
|
6924
|
+
...thinking ? { thinking } : {}
|
|
6885
6925
|
},
|
|
6886
6926
|
{ signal: this.abortController.signal }
|
|
6887
6927
|
);
|
|
@@ -6942,6 +6982,20 @@ class AnthropicProvider {
|
|
|
6942
6982
|
}
|
|
6943
6983
|
const finalMessage = await stream.finalMessage();
|
|
6944
6984
|
const assistantContent = [];
|
|
6985
|
+
for (const block of finalMessage.content) {
|
|
6986
|
+
if (block.type === "thinking") {
|
|
6987
|
+
assistantContent.push({
|
|
6988
|
+
type: "thinking",
|
|
6989
|
+
thinking: block.thinking,
|
|
6990
|
+
signature: block.signature
|
|
6991
|
+
});
|
|
6992
|
+
} else if (block.type === "redacted_thinking") {
|
|
6993
|
+
assistantContent.push({
|
|
6994
|
+
type: "redacted_thinking",
|
|
6995
|
+
data: block.data
|
|
6996
|
+
});
|
|
6997
|
+
}
|
|
6998
|
+
}
|
|
6945
6999
|
if (textContent) {
|
|
6946
7000
|
assistantContent.push({ type: "text", text: textContent });
|
|
6947
7001
|
}
|
|
@@ -7265,6 +7319,30 @@ function toOpenAITools(tools) {
|
|
|
7265
7319
|
function agentTemperatureForProfile(profile) {
|
|
7266
7320
|
return profile === "compact" ? 0.2 : void 0;
|
|
7267
7321
|
}
|
|
7322
|
+
function modelLikelySupportsOpenAIReasoningEffort(model) {
|
|
7323
|
+
return /^(?:o\d|o[1-9]|gpt-5|codex|computer-use)/i.test(model.trim());
|
|
7324
|
+
}
|
|
7325
|
+
function toOpenAIReasoningEffort(effort, providerId, model) {
|
|
7326
|
+
const supportsReasoningParam = providerId === "openrouter" || providerId === "custom" || providerId === "openai" && modelLikelySupportsOpenAIReasoningEffort(model);
|
|
7327
|
+
if (!supportsReasoningParam) return void 0;
|
|
7328
|
+
switch (effort) {
|
|
7329
|
+
case "off":
|
|
7330
|
+
if (providerId === "openai" && !/^gpt-5\.1/i.test(model.trim())) {
|
|
7331
|
+
return void 0;
|
|
7332
|
+
}
|
|
7333
|
+
return "none";
|
|
7334
|
+
case "low":
|
|
7335
|
+
return "low";
|
|
7336
|
+
case "medium":
|
|
7337
|
+
return "medium";
|
|
7338
|
+
case "high":
|
|
7339
|
+
return "high";
|
|
7340
|
+
case "max":
|
|
7341
|
+
return "xhigh";
|
|
7342
|
+
default:
|
|
7343
|
+
return void 0;
|
|
7344
|
+
}
|
|
7345
|
+
}
|
|
7268
7346
|
function followUpReminderForProfile(profile, userMessage, assistantText, latestToolResultPreview) {
|
|
7269
7347
|
if (profile !== "compact") return null;
|
|
7270
7348
|
const phaseReminder = buildPhaseReminder(userMessage, assistantText || "");
|
|
@@ -7875,6 +7953,7 @@ class OpenAICompatProvider {
|
|
|
7875
7953
|
client;
|
|
7876
7954
|
model;
|
|
7877
7955
|
providerId;
|
|
7956
|
+
reasoningEffort;
|
|
7878
7957
|
abortController = null;
|
|
7879
7958
|
constructor(config) {
|
|
7880
7959
|
const meta = PROVIDERS[config.id];
|
|
@@ -7892,6 +7971,7 @@ class OpenAICompatProvider {
|
|
|
7892
7971
|
});
|
|
7893
7972
|
this.providerId = config.id;
|
|
7894
7973
|
this.model = config.model || meta?.defaultModel || "gpt-4o";
|
|
7974
|
+
this.reasoningEffort = config.reasoningEffort ?? "off";
|
|
7895
7975
|
this.agentToolProfile = resolveAgentToolProfile(config);
|
|
7896
7976
|
}
|
|
7897
7977
|
async streamQuery(systemPrompt, userMessage, onChunk, onEnd, history) {
|
|
@@ -7901,13 +7981,19 @@ class OpenAICompatProvider {
|
|
|
7901
7981
|
...(history ?? []).map((m) => ({ role: m.role, content: m.content })),
|
|
7902
7982
|
{ role: "user", content: userMessage }
|
|
7903
7983
|
];
|
|
7984
|
+
const reasoningEffort = toOpenAIReasoningEffort(
|
|
7985
|
+
this.reasoningEffort,
|
|
7986
|
+
this.providerId,
|
|
7987
|
+
this.model
|
|
7988
|
+
);
|
|
7904
7989
|
try {
|
|
7905
7990
|
const stream = await this.client.chat.completions.create(
|
|
7906
7991
|
{
|
|
7907
7992
|
model: this.model,
|
|
7908
7993
|
max_tokens: 4096,
|
|
7909
7994
|
stream: true,
|
|
7910
|
-
messages
|
|
7995
|
+
messages,
|
|
7996
|
+
...reasoningEffort ? { reasoning_effort: reasoningEffort } : {}
|
|
7911
7997
|
},
|
|
7912
7998
|
{ signal: this.abortController.signal }
|
|
7913
7999
|
);
|
|
@@ -7945,6 +8031,11 @@ class OpenAICompatProvider {
|
|
|
7945
8031
|
...(history ?? []).map((m) => ({ role: m.role, content: m.content })),
|
|
7946
8032
|
{ role: "user", content: userMessage }
|
|
7947
8033
|
];
|
|
8034
|
+
const reasoningEffort = toOpenAIReasoningEffort(
|
|
8035
|
+
this.reasoningEffort,
|
|
8036
|
+
this.providerId,
|
|
8037
|
+
this.model
|
|
8038
|
+
);
|
|
7948
8039
|
try {
|
|
7949
8040
|
const maxIterations = getEffectiveMaxIterations();
|
|
7950
8041
|
let iterationsUsed = 0;
|
|
@@ -7972,7 +8063,8 @@ class OpenAICompatProvider {
|
|
|
7972
8063
|
messages,
|
|
7973
8064
|
tools: openAITools,
|
|
7974
8065
|
tool_choice: "auto",
|
|
7975
|
-
temperature: agentTemperatureForProfile(this.agentToolProfile)
|
|
8066
|
+
temperature: agentTemperatureForProfile(this.agentToolProfile),
|
|
8067
|
+
...reasoningEffort ? { reasoning_effort: reasoningEffort } : {}
|
|
7976
8068
|
},
|
|
7977
8069
|
{ signal: this.abortController.signal }
|
|
7978
8070
|
);
|
|
@@ -8267,9 +8359,13 @@ function sanitizeProviderConfig(config) {
|
|
|
8267
8359
|
...config,
|
|
8268
8360
|
apiKey: config.apiKey.trim(),
|
|
8269
8361
|
model: config.model.trim(),
|
|
8270
|
-
baseUrl: config.baseUrl?.trim() || void 0
|
|
8362
|
+
baseUrl: config.baseUrl?.trim() || void 0,
|
|
8363
|
+
reasoningEffort: sanitizeReasoningEffortLevel(config.reasoningEffort)
|
|
8271
8364
|
};
|
|
8272
8365
|
}
|
|
8366
|
+
function sanitizeReasoningEffortLevel(value) {
|
|
8367
|
+
return value === "low" || value === "medium" || value === "high" || value === "max" || value === "off" ? value : "off";
|
|
8368
|
+
}
|
|
8273
8369
|
function validateProviderConfig(config) {
|
|
8274
8370
|
return validateProviderConnection(config, { requireModel: true });
|
|
8275
8371
|
}
|
|
@@ -8371,7 +8467,11 @@ function createProvider(config) {
|
|
|
8371
8467
|
throw new Error(error);
|
|
8372
8468
|
}
|
|
8373
8469
|
if (normalized.id === "anthropic") {
|
|
8374
|
-
return new AnthropicProvider(
|
|
8470
|
+
return new AnthropicProvider(
|
|
8471
|
+
normalized.apiKey,
|
|
8472
|
+
normalized.model,
|
|
8473
|
+
normalized.reasoningEffort
|
|
8474
|
+
);
|
|
8375
8475
|
}
|
|
8376
8476
|
return new OpenAICompatProvider(normalized);
|
|
8377
8477
|
}
|
|
@@ -11759,6 +11859,41 @@ function exportBookmarksHtml(options = {}) {
|
|
|
11759
11859
|
return `${lines.join("\n")}
|
|
11760
11860
|
`;
|
|
11761
11861
|
}
|
|
11862
|
+
function exportBookmarkFolderHtml(folderId, options = {}) {
|
|
11863
|
+
const current = getState();
|
|
11864
|
+
const folder = current.folders.find((item) => item.id === folderId);
|
|
11865
|
+
if (!folder) return null;
|
|
11866
|
+
const resolvedOptions = {
|
|
11867
|
+
includeNotes: options.includeNotes ?? false
|
|
11868
|
+
};
|
|
11869
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
11870
|
+
const items = current.bookmarks.filter(
|
|
11871
|
+
(bookmark) => bookmark.folderId === folder.id
|
|
11872
|
+
);
|
|
11873
|
+
const addDate = toNetscapeTimestamp(folder.createdAt) || now;
|
|
11874
|
+
const lines = [
|
|
11875
|
+
NETSCAPE_BOOKMARKS_DOCTYPE,
|
|
11876
|
+
'<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">',
|
|
11877
|
+
`<TITLE>${escapeBookmarkHtml(folder.name)}</TITLE>`,
|
|
11878
|
+
`<H1>${escapeBookmarkHtml(folder.name)}</H1>`,
|
|
11879
|
+
"<DL><p>",
|
|
11880
|
+
` <DT><H3 ADD_DATE="${addDate}" LAST_MODIFIED="${now}">${escapeBookmarkHtml(folder.name)}</H3>`
|
|
11881
|
+
];
|
|
11882
|
+
if (resolvedOptions.includeNotes && folder.summary) {
|
|
11883
|
+
lines.push(` <DD>${escapeBookmarkHtml(folder.summary)}`);
|
|
11884
|
+
}
|
|
11885
|
+
lines.push(" <DL><p>");
|
|
11886
|
+
for (const bookmark of items) {
|
|
11887
|
+
appendBookmarkHtml(lines, bookmark, resolvedOptions, " ");
|
|
11888
|
+
}
|
|
11889
|
+
lines.push(" </DL><p>", "</DL><p>");
|
|
11890
|
+
return {
|
|
11891
|
+
content: `${lines.join("\n")}
|
|
11892
|
+
`,
|
|
11893
|
+
count: items.length,
|
|
11894
|
+
folderName: folder.name
|
|
11895
|
+
};
|
|
11896
|
+
}
|
|
11762
11897
|
function exportBookmarksJson() {
|
|
11763
11898
|
return `${JSON.stringify(getState(), null, 2)}
|
|
11764
11899
|
`;
|
|
@@ -24750,6 +24885,10 @@ function createSecondaryWindow() {
|
|
|
24750
24885
|
win.show();
|
|
24751
24886
|
return state2;
|
|
24752
24887
|
}
|
|
24888
|
+
function getSafeBookmarkExportName(name) {
|
|
24889
|
+
const safeName = name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
24890
|
+
return safeName || "folder";
|
|
24891
|
+
}
|
|
24753
24892
|
function registerBookmarkHandlers() {
|
|
24754
24893
|
electron.ipcMain.handle(Channels.BOOKMARKS_GET, () => {
|
|
24755
24894
|
return getState();
|
|
@@ -24828,6 +24967,29 @@ function registerBookmarkHandlers() {
|
|
|
24828
24967
|
count: getState().bookmarks.length
|
|
24829
24968
|
};
|
|
24830
24969
|
});
|
|
24970
|
+
electron.ipcMain.handle(
|
|
24971
|
+
Channels.FOLDER_EXPORT_HTML,
|
|
24972
|
+
async (_, folderId, options) => {
|
|
24973
|
+
const folder = getFolder(folderId);
|
|
24974
|
+
if (!folder) return null;
|
|
24975
|
+
const { canceled, filePath } = await electron.dialog.showSaveDialog({
|
|
24976
|
+
title: `Export ${folder.name}`,
|
|
24977
|
+
defaultPath: `vessel-bookmarks-${getSafeBookmarkExportName(folder.name)}.html`,
|
|
24978
|
+
filters: [{ name: "HTML Bookmarks", extensions: ["html"] }]
|
|
24979
|
+
});
|
|
24980
|
+
if (canceled || !filePath) return null;
|
|
24981
|
+
const result = exportBookmarkFolderHtml(folderId, {
|
|
24982
|
+
includeNotes: options?.includeNotes ?? true
|
|
24983
|
+
});
|
|
24984
|
+
if (!result) return null;
|
|
24985
|
+
await fs.promises.writeFile(filePath, result.content, "utf-8");
|
|
24986
|
+
trackBookmarkAction("export");
|
|
24987
|
+
return {
|
|
24988
|
+
filePath,
|
|
24989
|
+
count: result.count
|
|
24990
|
+
};
|
|
24991
|
+
}
|
|
24992
|
+
);
|
|
24831
24993
|
electron.ipcMain.handle(Channels.BOOKMARKS_IMPORT_HTML, async () => {
|
|
24832
24994
|
const { canceled, filePaths } = await electron.dialog.showOpenDialog({
|
|
24833
24995
|
title: "Import Bookmarks",
|
package/out/preload/index.js
CHANGED
|
@@ -67,6 +67,7 @@ const Channels = {
|
|
|
67
67
|
FOLDER_CREATE: "bookmarks:folder-create",
|
|
68
68
|
FOLDER_REMOVE: "bookmarks:folder-remove",
|
|
69
69
|
FOLDER_RENAME: "bookmarks:folder-rename",
|
|
70
|
+
FOLDER_EXPORT_HTML: "bookmarks:folder-export-html",
|
|
70
71
|
// Highlights
|
|
71
72
|
HIGHLIGHT_CAPTURE: "highlights:capture",
|
|
72
73
|
HIGHLIGHT_CAPTURE_RESULT: "highlights:capture-result",
|
|
@@ -359,6 +360,7 @@ const api = {
|
|
|
359
360
|
removeBookmark: (id) => electron.ipcRenderer.invoke(Channels.BOOKMARK_REMOVE, id),
|
|
360
361
|
exportHtml: (options) => electron.ipcRenderer.invoke(Channels.BOOKMARKS_EXPORT_HTML, options),
|
|
361
362
|
exportJson: () => electron.ipcRenderer.invoke(Channels.BOOKMARKS_EXPORT_JSON),
|
|
363
|
+
exportFolderHtml: (folderId, options) => electron.ipcRenderer.invoke(Channels.FOLDER_EXPORT_HTML, folderId, options),
|
|
362
364
|
importHtml: () => electron.ipcRenderer.invoke(Channels.BOOKMARKS_IMPORT_HTML),
|
|
363
365
|
importJson: () => electron.ipcRenderer.invoke(Channels.BOOKMARKS_IMPORT_JSON),
|
|
364
366
|
createFolder: (name) => electron.ipcRenderer.invoke(Channels.FOLDER_CREATE, name),
|