@quanta-intellect/vessel-browser 0.1.16 → 0.1.18
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/out/main/index.js
CHANGED
|
@@ -26,7 +26,15 @@ const defaults = {
|
|
|
26
26
|
chatProvider: null,
|
|
27
27
|
maxToolIterations: 200,
|
|
28
28
|
domainPolicy: { allowedDomains: [], blockedDomains: [] },
|
|
29
|
-
downloadPath: ""
|
|
29
|
+
downloadPath: "",
|
|
30
|
+
telemetryEnabled: true,
|
|
31
|
+
premium: {
|
|
32
|
+
status: "free",
|
|
33
|
+
customerId: "",
|
|
34
|
+
email: "",
|
|
35
|
+
validatedAt: "",
|
|
36
|
+
expiresAt: ""
|
|
37
|
+
}
|
|
30
38
|
};
|
|
31
39
|
const SETTABLE_KEYS = new Set(Object.keys(defaults));
|
|
32
40
|
let settings = null;
|
|
@@ -80,12 +88,9 @@ function loadSettings() {
|
|
|
80
88
|
return settings;
|
|
81
89
|
}
|
|
82
90
|
function saveSettings() {
|
|
83
|
-
|
|
84
|
-
fs.
|
|
85
|
-
|
|
86
|
-
} catch (err) {
|
|
87
|
-
console.error("[Vessel] Failed to save settings:", err);
|
|
88
|
-
}
|
|
91
|
+
fs.promises.mkdir(path.dirname(getSettingsPath()), { recursive: true }).then(
|
|
92
|
+
() => fs.promises.writeFile(getSettingsPath(), JSON.stringify(settings, null, 2))
|
|
93
|
+
).catch((err) => console.error("[Vessel] Failed to save settings:", err));
|
|
89
94
|
}
|
|
90
95
|
function setSetting(key, value) {
|
|
91
96
|
loadSettings();
|
|
@@ -528,11 +533,7 @@ function load$2() {
|
|
|
528
533
|
return state$3;
|
|
529
534
|
}
|
|
530
535
|
function save$2() {
|
|
531
|
-
|
|
532
|
-
fs.writeFileSync(getHighlightsPath(), JSON.stringify(state$3, null, 2), "utf-8");
|
|
533
|
-
} catch (err) {
|
|
534
|
-
console.error("[Vessel] Failed to save highlights:", err);
|
|
535
|
-
}
|
|
536
|
+
fs.promises.writeFile(getHighlightsPath(), JSON.stringify(state$3, null, 2), "utf-8").catch((err) => console.error("[Vessel] Failed to save highlights:", err));
|
|
536
537
|
}
|
|
537
538
|
function emit$2() {
|
|
538
539
|
if (!state$3) return;
|
|
@@ -1202,16 +1203,13 @@ function load$1() {
|
|
|
1202
1203
|
return state$2;
|
|
1203
1204
|
}
|
|
1204
1205
|
function save$1() {
|
|
1205
|
-
|
|
1206
|
-
fs.
|
|
1207
|
-
fs.writeFileSync(
|
|
1206
|
+
fs.promises.mkdir(path.dirname(getHistoryPath()), { recursive: true }).then(
|
|
1207
|
+
() => fs.promises.writeFile(
|
|
1208
1208
|
getHistoryPath(),
|
|
1209
1209
|
JSON.stringify(state$2, null, 2),
|
|
1210
1210
|
"utf-8"
|
|
1211
|
-
)
|
|
1212
|
-
|
|
1213
|
-
console.error("[Vessel] Failed to save history:", err);
|
|
1214
|
-
}
|
|
1211
|
+
)
|
|
1212
|
+
).catch((err) => console.error("[Vessel] Failed to save history:", err));
|
|
1215
1213
|
}
|
|
1216
1214
|
function emit$1() {
|
|
1217
1215
|
if (!state$2) return;
|
|
@@ -2344,6 +2342,13 @@ const Channels = {
|
|
|
2344
2342
|
DOWNLOAD_STARTED: "download:started",
|
|
2345
2343
|
DOWNLOAD_PROGRESS: "download:progress",
|
|
2346
2344
|
DOWNLOAD_DONE: "download:done",
|
|
2345
|
+
// Premium
|
|
2346
|
+
PREMIUM_GET_STATE: "premium:get-state",
|
|
2347
|
+
PREMIUM_ACTIVATE: "premium:activate",
|
|
2348
|
+
PREMIUM_CHECKOUT: "premium:checkout",
|
|
2349
|
+
PREMIUM_PORTAL: "premium:portal",
|
|
2350
|
+
PREMIUM_RESET: "premium:reset",
|
|
2351
|
+
PREMIUM_UPDATE: "premium:update",
|
|
2347
2352
|
// Window controls
|
|
2348
2353
|
WINDOW_MINIMIZE: "window:minimize",
|
|
2349
2354
|
WINDOW_MAXIMIZE: "window:maximize",
|
|
@@ -4406,6 +4411,288 @@ function setMcpHealth(update) {
|
|
|
4406
4411
|
}
|
|
4407
4412
|
}
|
|
4408
4413
|
}
|
|
4414
|
+
const VERIFICATION_API = process.env.VESSEL_PREMIUM_API || "https://vesselpremium.quantaintellect.com";
|
|
4415
|
+
const FREE_TOOL_ITERATION_LIMIT = 50;
|
|
4416
|
+
const REVALIDATION_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
4417
|
+
const OFFLINE_GRACE_PERIOD_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
4418
|
+
const PREMIUM_TOOLS = /* @__PURE__ */ new Set([
|
|
4419
|
+
"screenshot",
|
|
4420
|
+
"save_session",
|
|
4421
|
+
"load_session",
|
|
4422
|
+
"list_sessions",
|
|
4423
|
+
"delete_session",
|
|
4424
|
+
"flow_start",
|
|
4425
|
+
"flow_advance",
|
|
4426
|
+
"flow_status",
|
|
4427
|
+
"flow_end",
|
|
4428
|
+
"metrics",
|
|
4429
|
+
"extract_table"
|
|
4430
|
+
]);
|
|
4431
|
+
function isPremium() {
|
|
4432
|
+
const { premium } = loadSettings();
|
|
4433
|
+
if (premium.status === "active" || premium.status === "trialing") {
|
|
4434
|
+
return true;
|
|
4435
|
+
}
|
|
4436
|
+
if (premium.validatedAt && premium.status !== "free") {
|
|
4437
|
+
const lastValidated = new Date(premium.validatedAt).getTime();
|
|
4438
|
+
if (Date.now() - lastValidated < OFFLINE_GRACE_PERIOD_MS) {
|
|
4439
|
+
return true;
|
|
4440
|
+
}
|
|
4441
|
+
}
|
|
4442
|
+
return false;
|
|
4443
|
+
}
|
|
4444
|
+
function getPremiumState() {
|
|
4445
|
+
return { ...loadSettings().premium };
|
|
4446
|
+
}
|
|
4447
|
+
function getEffectiveMaxIterations() {
|
|
4448
|
+
if (isPremium()) {
|
|
4449
|
+
return loadSettings().maxToolIterations || 200;
|
|
4450
|
+
}
|
|
4451
|
+
return FREE_TOOL_ITERATION_LIMIT;
|
|
4452
|
+
}
|
|
4453
|
+
function resetPremium() {
|
|
4454
|
+
const fresh = {
|
|
4455
|
+
status: "free",
|
|
4456
|
+
customerId: "",
|
|
4457
|
+
email: "",
|
|
4458
|
+
validatedAt: "",
|
|
4459
|
+
expiresAt: ""
|
|
4460
|
+
};
|
|
4461
|
+
setSetting("premium", fresh);
|
|
4462
|
+
return fresh;
|
|
4463
|
+
}
|
|
4464
|
+
function isToolGated(toolName) {
|
|
4465
|
+
return PREMIUM_TOOLS.has(toolName) && !isPremium();
|
|
4466
|
+
}
|
|
4467
|
+
async function getCheckoutUrl(email) {
|
|
4468
|
+
try {
|
|
4469
|
+
const params = new URLSearchParams();
|
|
4470
|
+
if (email) params.set("email", email);
|
|
4471
|
+
const res = await fetch(`${VERIFICATION_API}/checkout?${params}`, {
|
|
4472
|
+
method: "POST",
|
|
4473
|
+
headers: { "Content-Type": "application/json" }
|
|
4474
|
+
});
|
|
4475
|
+
if (!res.ok) {
|
|
4476
|
+
const body = await res.text();
|
|
4477
|
+
return { ok: false, error: body || `HTTP ${res.status}` };
|
|
4478
|
+
}
|
|
4479
|
+
const { url } = await res.json();
|
|
4480
|
+
return { ok: true, url };
|
|
4481
|
+
} catch (err) {
|
|
4482
|
+
return {
|
|
4483
|
+
ok: false,
|
|
4484
|
+
error: err instanceof Error ? err.message : "Failed to create checkout"
|
|
4485
|
+
};
|
|
4486
|
+
}
|
|
4487
|
+
}
|
|
4488
|
+
async function getPortalUrl() {
|
|
4489
|
+
const { premium } = loadSettings();
|
|
4490
|
+
if (!premium.customerId) {
|
|
4491
|
+
return { ok: false, error: "No active subscription" };
|
|
4492
|
+
}
|
|
4493
|
+
try {
|
|
4494
|
+
const res = await fetch(`${VERIFICATION_API}/portal`, {
|
|
4495
|
+
method: "POST",
|
|
4496
|
+
headers: { "Content-Type": "application/json" },
|
|
4497
|
+
body: JSON.stringify({ customerId: premium.customerId })
|
|
4498
|
+
});
|
|
4499
|
+
if (!res.ok) {
|
|
4500
|
+
return { ok: false, error: `HTTP ${res.status}` };
|
|
4501
|
+
}
|
|
4502
|
+
const { url } = await res.json();
|
|
4503
|
+
return { ok: true, url };
|
|
4504
|
+
} catch (err) {
|
|
4505
|
+
return {
|
|
4506
|
+
ok: false,
|
|
4507
|
+
error: err instanceof Error ? err.message : "Failed to get portal URL"
|
|
4508
|
+
};
|
|
4509
|
+
}
|
|
4510
|
+
}
|
|
4511
|
+
async function verifySubscription(emailOrCustomerId) {
|
|
4512
|
+
const current = loadSettings().premium;
|
|
4513
|
+
const identifier = emailOrCustomerId || current.customerId || current.email;
|
|
4514
|
+
if (!identifier) {
|
|
4515
|
+
return current;
|
|
4516
|
+
}
|
|
4517
|
+
try {
|
|
4518
|
+
const res = await fetch(`${VERIFICATION_API}/verify`, {
|
|
4519
|
+
method: "POST",
|
|
4520
|
+
headers: { "Content-Type": "application/json" },
|
|
4521
|
+
body: JSON.stringify({ identifier })
|
|
4522
|
+
});
|
|
4523
|
+
if (!res.ok) {
|
|
4524
|
+
console.warn("[Vessel Premium] Verification API returned", res.status);
|
|
4525
|
+
return current;
|
|
4526
|
+
}
|
|
4527
|
+
const data = await res.json();
|
|
4528
|
+
const updated = {
|
|
4529
|
+
status: data.status,
|
|
4530
|
+
customerId: data.customerId,
|
|
4531
|
+
email: data.email,
|
|
4532
|
+
validatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4533
|
+
expiresAt: data.expiresAt
|
|
4534
|
+
};
|
|
4535
|
+
setSetting("premium", updated);
|
|
4536
|
+
return updated;
|
|
4537
|
+
} catch (err) {
|
|
4538
|
+
console.warn("[Vessel Premium] Verification failed:", err);
|
|
4539
|
+
return current;
|
|
4540
|
+
}
|
|
4541
|
+
}
|
|
4542
|
+
async function activateWithEmail(email) {
|
|
4543
|
+
if (!email.trim()) {
|
|
4544
|
+
return { ok: false, state: getPremiumState(), error: "Email is required" };
|
|
4545
|
+
}
|
|
4546
|
+
const state2 = await verifySubscription(email.trim());
|
|
4547
|
+
if (state2.status === "active" || state2.status === "trialing") {
|
|
4548
|
+
return { ok: true, state: state2 };
|
|
4549
|
+
}
|
|
4550
|
+
return {
|
|
4551
|
+
ok: false,
|
|
4552
|
+
state: state2,
|
|
4553
|
+
error: state2.status === "canceled" ? "Subscription is canceled. Resubscribe to continue." : state2.status === "past_due" ? "Subscription payment is past due. Update your payment method." : "No active subscription found for this email."
|
|
4554
|
+
};
|
|
4555
|
+
}
|
|
4556
|
+
let revalidationTimer = null;
|
|
4557
|
+
function startBackgroundRevalidation() {
|
|
4558
|
+
if (revalidationTimer) return;
|
|
4559
|
+
const { premium } = loadSettings();
|
|
4560
|
+
if (premium.customerId || premium.email) {
|
|
4561
|
+
const lastValidated = premium.validatedAt ? new Date(premium.validatedAt).getTime() : 0;
|
|
4562
|
+
if (Date.now() - lastValidated > REVALIDATION_INTERVAL_MS) {
|
|
4563
|
+
void verifySubscription();
|
|
4564
|
+
}
|
|
4565
|
+
}
|
|
4566
|
+
revalidationTimer = setInterval(() => {
|
|
4567
|
+
const { premium: p } = loadSettings();
|
|
4568
|
+
if (p.customerId || p.email) {
|
|
4569
|
+
void verifySubscription();
|
|
4570
|
+
}
|
|
4571
|
+
}, REVALIDATION_INTERVAL_MS);
|
|
4572
|
+
}
|
|
4573
|
+
function stopBackgroundRevalidation() {
|
|
4574
|
+
if (revalidationTimer) {
|
|
4575
|
+
clearInterval(revalidationTimer);
|
|
4576
|
+
revalidationTimer = null;
|
|
4577
|
+
}
|
|
4578
|
+
}
|
|
4579
|
+
const POSTHOG_API_KEY = process.env.POSTHOG_API_KEY || "phc_OMeM3P5cxJwl14lOKxYad0Yre52xvjNfkLEFnPtXyM";
|
|
4580
|
+
const POSTHOG_HOST = process.env.POSTHOG_HOST || "https://us.i.posthog.com";
|
|
4581
|
+
const BATCH_INTERVAL_MS = 6e4;
|
|
4582
|
+
const MAX_BATCH_SIZE = 50;
|
|
4583
|
+
function getDeviceIdPath() {
|
|
4584
|
+
return path.join(electron.app.getPath("userData"), ".vessel-device-id");
|
|
4585
|
+
}
|
|
4586
|
+
let deviceId = null;
|
|
4587
|
+
function getDeviceId() {
|
|
4588
|
+
if (deviceId) return deviceId;
|
|
4589
|
+
const idPath = getDeviceIdPath();
|
|
4590
|
+
try {
|
|
4591
|
+
deviceId = fs.readFileSync(idPath, "utf-8").trim();
|
|
4592
|
+
if (deviceId) return deviceId;
|
|
4593
|
+
} catch {
|
|
4594
|
+
}
|
|
4595
|
+
deviceId = crypto.randomUUID();
|
|
4596
|
+
try {
|
|
4597
|
+
fs.mkdirSync(path.dirname(idPath), { recursive: true });
|
|
4598
|
+
fs.writeFileSync(idPath, deviceId, "utf-8");
|
|
4599
|
+
} catch {
|
|
4600
|
+
}
|
|
4601
|
+
return deviceId;
|
|
4602
|
+
}
|
|
4603
|
+
let eventQueue = [];
|
|
4604
|
+
let flushTimer = null;
|
|
4605
|
+
let sessionStartedAt = null;
|
|
4606
|
+
function isEnabled() {
|
|
4607
|
+
if (POSTHOG_API_KEY === "YOUR_POSTHOG_KEY_HERE") return false;
|
|
4608
|
+
return loadSettings().telemetryEnabled !== false;
|
|
4609
|
+
}
|
|
4610
|
+
function trackEvent(event, properties = {}) {
|
|
4611
|
+
if (!isEnabled()) return;
|
|
4612
|
+
eventQueue.push({
|
|
4613
|
+
event,
|
|
4614
|
+
properties: {
|
|
4615
|
+
...properties,
|
|
4616
|
+
premium_status: isPremium() ? "premium" : "free",
|
|
4617
|
+
app_version: electron.app.getVersion(),
|
|
4618
|
+
platform: process.platform,
|
|
4619
|
+
arch: process.arch
|
|
4620
|
+
},
|
|
4621
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
4622
|
+
});
|
|
4623
|
+
if (eventQueue.length >= MAX_BATCH_SIZE) {
|
|
4624
|
+
void flush();
|
|
4625
|
+
}
|
|
4626
|
+
}
|
|
4627
|
+
function trackToolCall(toolName, pageType) {
|
|
4628
|
+
trackEvent("tool_called", {
|
|
4629
|
+
tool_name: toolName,
|
|
4630
|
+
page_type: "unknown"
|
|
4631
|
+
});
|
|
4632
|
+
}
|
|
4633
|
+
function trackProviderConfigured(providerId) {
|
|
4634
|
+
trackEvent("provider_configured", {
|
|
4635
|
+
provider_id: providerId
|
|
4636
|
+
});
|
|
4637
|
+
}
|
|
4638
|
+
function startTelemetry() {
|
|
4639
|
+
if (!isEnabled()) return;
|
|
4640
|
+
sessionStartedAt = Date.now();
|
|
4641
|
+
trackEvent("app_launched", {
|
|
4642
|
+
electron_version: process.versions.electron,
|
|
4643
|
+
chrome_version: process.versions.chrome
|
|
4644
|
+
});
|
|
4645
|
+
flushTimer = setInterval(() => {
|
|
4646
|
+
void flush();
|
|
4647
|
+
}, BATCH_INTERVAL_MS);
|
|
4648
|
+
}
|
|
4649
|
+
function stopTelemetry() {
|
|
4650
|
+
if (sessionStartedAt) {
|
|
4651
|
+
const durationMinutes = Math.round(
|
|
4652
|
+
(Date.now() - sessionStartedAt) / 6e4
|
|
4653
|
+
);
|
|
4654
|
+
trackEvent("app_session_ended", {
|
|
4655
|
+
duration_minutes: durationMinutes
|
|
4656
|
+
});
|
|
4657
|
+
sessionStartedAt = null;
|
|
4658
|
+
}
|
|
4659
|
+
if (flushTimer) {
|
|
4660
|
+
clearInterval(flushTimer);
|
|
4661
|
+
flushTimer = null;
|
|
4662
|
+
}
|
|
4663
|
+
void flush();
|
|
4664
|
+
}
|
|
4665
|
+
async function flush() {
|
|
4666
|
+
if (eventQueue.length === 0) return;
|
|
4667
|
+
if (!isEnabled()) {
|
|
4668
|
+
eventQueue = [];
|
|
4669
|
+
return;
|
|
4670
|
+
}
|
|
4671
|
+
const batch = eventQueue.splice(0);
|
|
4672
|
+
const distinctId = getDeviceId();
|
|
4673
|
+
const payload = {
|
|
4674
|
+
api_key: POSTHOG_API_KEY,
|
|
4675
|
+
batch: batch.map((e) => ({
|
|
4676
|
+
event: e.event,
|
|
4677
|
+
properties: {
|
|
4678
|
+
distinct_id: distinctId,
|
|
4679
|
+
...e.properties
|
|
4680
|
+
},
|
|
4681
|
+
timestamp: e.timestamp
|
|
4682
|
+
}))
|
|
4683
|
+
};
|
|
4684
|
+
try {
|
|
4685
|
+
await fetch(`${POSTHOG_HOST}/batch`, {
|
|
4686
|
+
method: "POST",
|
|
4687
|
+
headers: { "Content-Type": "application/json" },
|
|
4688
|
+
body: JSON.stringify(payload)
|
|
4689
|
+
});
|
|
4690
|
+
} catch {
|
|
4691
|
+
if (eventQueue.length < MAX_BATCH_SIZE * 2) {
|
|
4692
|
+
eventQueue.unshift(...batch);
|
|
4693
|
+
}
|
|
4694
|
+
}
|
|
4695
|
+
}
|
|
4409
4696
|
function isRichToolResult(value) {
|
|
4410
4697
|
return typeof value === "object" && value !== null && value.__richResult === true;
|
|
4411
4698
|
}
|
|
@@ -4419,7 +4706,6 @@ function makeImageResult(base64, description, mediaType = "image/png") {
|
|
|
4419
4706
|
};
|
|
4420
4707
|
return JSON.stringify(result);
|
|
4421
4708
|
}
|
|
4422
|
-
const DEFAULT_MAX_ITERATIONS$1 = 200;
|
|
4423
4709
|
class AnthropicProvider {
|
|
4424
4710
|
client;
|
|
4425
4711
|
model;
|
|
@@ -4467,7 +4753,7 @@ class AnthropicProvider {
|
|
|
4467
4753
|
{ role: "user", content: userMessage }
|
|
4468
4754
|
];
|
|
4469
4755
|
try {
|
|
4470
|
-
const maxIterations =
|
|
4756
|
+
const maxIterations = getEffectiveMaxIterations();
|
|
4471
4757
|
let iterationsUsed = 0;
|
|
4472
4758
|
for (let i = 0; i < maxIterations; i++) {
|
|
4473
4759
|
iterationsUsed = i + 1;
|
|
@@ -4708,7 +4994,6 @@ const PROVIDERS = {
|
|
|
4708
4994
|
apiKeyHint: "Any OpenAI-compatible API endpoint"
|
|
4709
4995
|
}
|
|
4710
4996
|
};
|
|
4711
|
-
const DEFAULT_MAX_ITERATIONS = 200;
|
|
4712
4997
|
function toOpenAITools(tools) {
|
|
4713
4998
|
return tools.map((t) => ({
|
|
4714
4999
|
type: "function",
|
|
@@ -4774,7 +5059,7 @@ class OpenAICompatProvider {
|
|
|
4774
5059
|
{ role: "user", content: userMessage }
|
|
4775
5060
|
];
|
|
4776
5061
|
try {
|
|
4777
|
-
const maxIterations =
|
|
5062
|
+
const maxIterations = getEffectiveMaxIterations();
|
|
4778
5063
|
let iterationsUsed = 0;
|
|
4779
5064
|
for (let i = 0; i < maxIterations; i++) {
|
|
4780
5065
|
iterationsUsed = i + 1;
|
|
@@ -7285,7 +7570,7 @@ function pruneToolsForContext(tools, pageType, query = "") {
|
|
|
7285
7570
|
const ctx = pageType ?? "GENERAL";
|
|
7286
7571
|
const hints = CONTEXT_HINTS[ctx] ?? {};
|
|
7287
7572
|
const intents = inferIntent(query);
|
|
7288
|
-
const scored = tools.filter((tool) => shouldIncludeTool(tool.name, ctx, intents)).map((tool) => ({
|
|
7573
|
+
const scored = tools.filter((tool) => !isToolGated(tool.name)).filter((tool) => shouldIncludeTool(tool.name, ctx, intents)).map((tool) => ({
|
|
7289
7574
|
tool,
|
|
7290
7575
|
score: scoreForContext(tool.name, ctx)
|
|
7291
7576
|
}));
|
|
@@ -7460,12 +7745,13 @@ function load() {
|
|
|
7460
7745
|
return state;
|
|
7461
7746
|
}
|
|
7462
7747
|
function save() {
|
|
7463
|
-
|
|
7464
|
-
fs.
|
|
7465
|
-
|
|
7466
|
-
|
|
7467
|
-
|
|
7468
|
-
|
|
7748
|
+
fs.promises.mkdir(path.dirname(getBookmarksPath()), { recursive: true }).then(
|
|
7749
|
+
() => fs.promises.writeFile(
|
|
7750
|
+
getBookmarksPath(),
|
|
7751
|
+
JSON.stringify(state, null, 2),
|
|
7752
|
+
"utf-8"
|
|
7753
|
+
)
|
|
7754
|
+
).catch((err) => console.error("[Vessel] Failed to save bookmarks:", err));
|
|
7469
7755
|
}
|
|
7470
7756
|
function emit() {
|
|
7471
7757
|
if (!state) return;
|
|
@@ -10782,6 +11068,10 @@ async function executeAction(name, args, ctx) {
|
|
|
10782
11068
|
].includes(name)) {
|
|
10783
11069
|
return "Error: No active tab";
|
|
10784
11070
|
}
|
|
11071
|
+
trackToolCall(name);
|
|
11072
|
+
if (isToolGated(name)) {
|
|
11073
|
+
return `This tool (${name}) requires Vessel Premium. Upgrade at Settings > Premium to unlock screenshot, session management, workflow tracking, and more.`;
|
|
11074
|
+
}
|
|
10785
11075
|
const wc = tab?.view.webContents;
|
|
10786
11076
|
const result = await ctx.runtime.runControlledAction({
|
|
10787
11077
|
source: "ai",
|
|
@@ -17236,15 +17526,18 @@ function startMcpServer(tabManager, runtime2, port) {
|
|
|
17236
17526
|
res.end("Not found");
|
|
17237
17527
|
return;
|
|
17238
17528
|
}
|
|
17239
|
-
|
|
17240
|
-
|
|
17241
|
-
"Access-Control-Allow-
|
|
17242
|
-
|
|
17243
|
-
|
|
17244
|
-
|
|
17245
|
-
|
|
17246
|
-
|
|
17247
|
-
|
|
17529
|
+
const origin = req.headers.origin;
|
|
17530
|
+
if (origin && /^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/.test(origin)) {
|
|
17531
|
+
res.setHeader("Access-Control-Allow-Origin", origin);
|
|
17532
|
+
res.setHeader(
|
|
17533
|
+
"Access-Control-Allow-Methods",
|
|
17534
|
+
"POST, GET, DELETE, OPTIONS"
|
|
17535
|
+
);
|
|
17536
|
+
res.setHeader(
|
|
17537
|
+
"Access-Control-Allow-Headers",
|
|
17538
|
+
"Content-Type, mcp-session-id, Authorization"
|
|
17539
|
+
);
|
|
17540
|
+
}
|
|
17248
17541
|
if (req.method === "OPTIONS") {
|
|
17249
17542
|
res.writeHead(204);
|
|
17250
17543
|
res.end();
|
|
@@ -17404,6 +17697,7 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
17404
17697
|
}
|
|
17405
17698
|
try {
|
|
17406
17699
|
activeChatProvider = createProvider(chatConfig);
|
|
17700
|
+
trackProviderConfigured(chatConfig.id);
|
|
17407
17701
|
const activeTab = tabManager.getActiveTab();
|
|
17408
17702
|
await handleAIQuery(
|
|
17409
17703
|
query,
|
|
@@ -17704,6 +17998,35 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
17704
17998
|
layoutViews(windowState);
|
|
17705
17999
|
return clamped;
|
|
17706
18000
|
});
|
|
18001
|
+
electron.ipcMain.handle(Channels.PREMIUM_GET_STATE, () => {
|
|
18002
|
+
return getPremiumState();
|
|
18003
|
+
});
|
|
18004
|
+
electron.ipcMain.handle(Channels.PREMIUM_ACTIVATE, async (_, email) => {
|
|
18005
|
+
const result = await activateWithEmail(email);
|
|
18006
|
+
if (result.ok) {
|
|
18007
|
+
sendToRendererViews(Channels.PREMIUM_UPDATE, result.state);
|
|
18008
|
+
}
|
|
18009
|
+
return result;
|
|
18010
|
+
});
|
|
18011
|
+
electron.ipcMain.handle(Channels.PREMIUM_CHECKOUT, async (_, email) => {
|
|
18012
|
+
const result = await getCheckoutUrl(email);
|
|
18013
|
+
if (result.ok && result.url) {
|
|
18014
|
+
tabManager.createTab(result.url);
|
|
18015
|
+
}
|
|
18016
|
+
return result;
|
|
18017
|
+
});
|
|
18018
|
+
electron.ipcMain.handle(Channels.PREMIUM_RESET, () => {
|
|
18019
|
+
const state2 = resetPremium();
|
|
18020
|
+
sendToRendererViews(Channels.PREMIUM_UPDATE, state2);
|
|
18021
|
+
return state2;
|
|
18022
|
+
});
|
|
18023
|
+
electron.ipcMain.handle(Channels.PREMIUM_PORTAL, async () => {
|
|
18024
|
+
const result = await getPortalUrl();
|
|
18025
|
+
if (result.ok && result.url) {
|
|
18026
|
+
tabManager.createTab(result.url);
|
|
18027
|
+
}
|
|
18028
|
+
return result;
|
|
18029
|
+
});
|
|
17707
18030
|
electron.ipcMain.handle(Channels.WINDOW_MINIMIZE, () => {
|
|
17708
18031
|
mainWindow.minimize();
|
|
17709
18032
|
});
|
|
@@ -18076,16 +18399,15 @@ ${progress}
|
|
|
18076
18399
|
actions: this.state.actions.slice(-120),
|
|
18077
18400
|
checkpoints: this.state.checkpoints.slice(-20)
|
|
18078
18401
|
};
|
|
18079
|
-
|
|
18080
|
-
fs$1.
|
|
18081
|
-
fs$1.writeFileSync(
|
|
18402
|
+
return fs$1.promises.mkdir(path$1.dirname(getRuntimeStatePath()), { recursive: true }).then(
|
|
18403
|
+
() => fs$1.promises.writeFile(
|
|
18082
18404
|
getRuntimeStatePath(),
|
|
18083
18405
|
JSON.stringify(persisted, null, 2),
|
|
18084
18406
|
"utf-8"
|
|
18085
|
-
)
|
|
18086
|
-
|
|
18087
|
-
console.error("[Vessel] Failed to persist runtime state:", err)
|
|
18088
|
-
|
|
18407
|
+
)
|
|
18408
|
+
).catch(
|
|
18409
|
+
(err) => console.error("[Vessel] Failed to persist runtime state:", err)
|
|
18410
|
+
);
|
|
18089
18411
|
}
|
|
18090
18412
|
schedulePersist() {
|
|
18091
18413
|
this.persistDirty = true;
|
|
@@ -18097,7 +18419,7 @@ ${progress}
|
|
|
18097
18419
|
}
|
|
18098
18420
|
/** Flush any pending debounced persist to disk immediately. Call on shutdown. */
|
|
18099
18421
|
flushPersist() {
|
|
18100
|
-
|
|
18422
|
+
return this.persistDirty ? this.persistNow() : Promise.resolve();
|
|
18101
18423
|
}
|
|
18102
18424
|
emit() {
|
|
18103
18425
|
this.schedulePersist();
|
|
@@ -18473,6 +18795,8 @@ async function bootstrap() {
|
|
|
18473
18795
|
sidebarView.webContents.send(Channels.HISTORY_UPDATE, state2);
|
|
18474
18796
|
});
|
|
18475
18797
|
installDownloadHandler(chromeView);
|
|
18798
|
+
startBackgroundRevalidation();
|
|
18799
|
+
startTelemetry();
|
|
18476
18800
|
const chromeUrl = rendererUrlFor("chrome");
|
|
18477
18801
|
const sidebarUrl = rendererUrlFor("sidebar");
|
|
18478
18802
|
const devtoolsUrl = rendererUrlFor("devtools");
|
|
@@ -18512,6 +18836,8 @@ electron.app.whenReady().then(bootstrap).catch((error) => {
|
|
|
18512
18836
|
});
|
|
18513
18837
|
electron.app.on("window-all-closed", () => {
|
|
18514
18838
|
electron.globalShortcut.unregisterAll();
|
|
18839
|
+
stopTelemetry();
|
|
18840
|
+
stopBackgroundRevalidation();
|
|
18515
18841
|
runtime?.flushPersist();
|
|
18516
18842
|
void stopMcpServer().finally(() => {
|
|
18517
18843
|
electron.app.quit();
|
package/out/preload/index.js
CHANGED
|
@@ -74,6 +74,13 @@ const Channels = {
|
|
|
74
74
|
HISTORY_SEARCH: "history:search",
|
|
75
75
|
HISTORY_CLEAR: "history:clear",
|
|
76
76
|
HISTORY_UPDATE: "history:update",
|
|
77
|
+
// Premium
|
|
78
|
+
PREMIUM_GET_STATE: "premium:get-state",
|
|
79
|
+
PREMIUM_ACTIVATE: "premium:activate",
|
|
80
|
+
PREMIUM_CHECKOUT: "premium:checkout",
|
|
81
|
+
PREMIUM_PORTAL: "premium:portal",
|
|
82
|
+
PREMIUM_RESET: "premium:reset",
|
|
83
|
+
PREMIUM_UPDATE: "premium:update",
|
|
77
84
|
// Window controls
|
|
78
85
|
WINDOW_MINIMIZE: "window:minimize",
|
|
79
86
|
WINDOW_MAXIMIZE: "window:maximize",
|
|
@@ -223,6 +230,18 @@ const api = {
|
|
|
223
230
|
return () => electron.ipcRenderer.removeListener(Channels.HISTORY_UPDATE, handler);
|
|
224
231
|
}
|
|
225
232
|
},
|
|
233
|
+
premium: {
|
|
234
|
+
getState: () => electron.ipcRenderer.invoke(Channels.PREMIUM_GET_STATE),
|
|
235
|
+
activate: (email) => electron.ipcRenderer.invoke(Channels.PREMIUM_ACTIVATE, email),
|
|
236
|
+
checkout: (email) => electron.ipcRenderer.invoke(Channels.PREMIUM_CHECKOUT, email),
|
|
237
|
+
portal: () => electron.ipcRenderer.invoke(Channels.PREMIUM_PORTAL),
|
|
238
|
+
reset: () => electron.ipcRenderer.invoke(Channels.PREMIUM_RESET),
|
|
239
|
+
onUpdate: (cb) => {
|
|
240
|
+
const handler = (_, state) => cb(state);
|
|
241
|
+
electron.ipcRenderer.on(Channels.PREMIUM_UPDATE, handler);
|
|
242
|
+
return () => electron.ipcRenderer.removeListener(Channels.PREMIUM_UPDATE, handler);
|
|
243
|
+
}
|
|
244
|
+
},
|
|
226
245
|
window: {
|
|
227
246
|
minimize: () => electron.ipcRenderer.invoke(Channels.WINDOW_MINIMIZE),
|
|
228
247
|
maximize: () => electron.ipcRenderer.invoke(Channels.WINDOW_MAXIMIZE),
|