@quanta-intellect/vessel-browser 0.1.31 → 0.1.33
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 +14 -1
- package/out/main/index.js +397 -23
- package/out/preload/index.js +1 -1
- package/out/renderer/assets/{index-DVD9XuhC.js → index-BFdOm6Op.js} +101 -24
- package/out/renderer/index.html +1 -1
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
</div>
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
Open source chromium-based browser for persistent web agents
|
|
14
|
+
Open source chromium-based browser for persistent web agents. Linux is the most mature install target today, and macOS release packaging is available from source.
|
|
15
15
|
|
|
16
16
|
Vessel gives external agent harnesses a real browser with durable state, MCP control, and a human-visible supervisory UI. It is built for long-running workflows where the agent drives and the human audits, intervenes, and redirects when needed.
|
|
17
17
|
|
|
@@ -200,12 +200,25 @@ npm run dist:dir
|
|
|
200
200
|
|
|
201
201
|
# Package a Linux AppImage
|
|
202
202
|
npm run dist
|
|
203
|
+
|
|
204
|
+
# Package an unpacked macOS app bundle (run on macOS)
|
|
205
|
+
npm run dist:mac:dir
|
|
206
|
+
|
|
207
|
+
# Package macOS DMG + ZIP artifacts (run on macOS)
|
|
208
|
+
npm run dist:mac
|
|
209
|
+
|
|
210
|
+
# Package signed macOS DMG + ZIP artifacts (run on macOS with signing set up)
|
|
211
|
+
npm run dist:mac:signed
|
|
203
212
|
```
|
|
204
213
|
|
|
205
214
|
Notes:
|
|
206
215
|
|
|
207
216
|
- `npm run dev` still launches the stock Electron binary, so Linux may continue showing the default Electron gear icon in development
|
|
208
217
|
- packaged builds created with `npm run dist` / `npm run dist:dir` use the Vessel app icon
|
|
218
|
+
- `npm run build:icon:mac` regenerates `resources/vessel-icon.icns` from `resources/vessel-icon.png` for macOS packaging
|
|
219
|
+
- `npm run dist:mac` and `npm run dist:mac:dir` intentionally disable auto-signing so local packaging works on any Mac without keychain setup
|
|
220
|
+
- `npm run dist:mac:signed` and `npm run dist:mac:dir:signed` use normal `electron-builder` signing discovery; if your login keychain has duplicate Apple certs, clean those up or use a dedicated keychain before running the signed path
|
|
221
|
+
- signed builds are still not notarized by this repo out of the box, so Gatekeeper warnings remain until notarization is added for release publishing
|
|
209
222
|
- the tracked smoke test runs typecheck, build, the MCP stdio proxy regression check, and the Electron navigation regression harness
|
|
210
223
|
- for headless CI, run the smoke test under `xvfb-run -a npm run smoke:test`
|
|
211
224
|
|
package/out/main/index.js
CHANGED
|
@@ -11509,6 +11509,325 @@ async function submitForm$1(wc, args) {
|
|
|
11509
11509
|
async function clickElementBySelector(wc, selector) {
|
|
11510
11510
|
return clickResolvedSelector$1(wc, selector);
|
|
11511
11511
|
}
|
|
11512
|
+
const HUGGING_FACE_HUB_HOSTS = /* @__PURE__ */ new Set(["huggingface.co", "www.huggingface.co"]);
|
|
11513
|
+
const HUGGING_FACE_MODEL_TASKS = [
|
|
11514
|
+
{
|
|
11515
|
+
value: "automatic-speech-recognition",
|
|
11516
|
+
label: "automatic speech recognition",
|
|
11517
|
+
phrases: ["automatic speech recognition", "speech recognition", "asr"]
|
|
11518
|
+
},
|
|
11519
|
+
{
|
|
11520
|
+
value: "text-classification",
|
|
11521
|
+
label: "text classification",
|
|
11522
|
+
phrases: ["text classification", "classification"]
|
|
11523
|
+
},
|
|
11524
|
+
{
|
|
11525
|
+
value: "token-classification",
|
|
11526
|
+
label: "token classification",
|
|
11527
|
+
phrases: ["token classification", "named entity recognition", "ner"]
|
|
11528
|
+
},
|
|
11529
|
+
{
|
|
11530
|
+
value: "question-answering",
|
|
11531
|
+
label: "question answering",
|
|
11532
|
+
phrases: ["question answering", "qa"]
|
|
11533
|
+
},
|
|
11534
|
+
{
|
|
11535
|
+
value: "sentence-similarity",
|
|
11536
|
+
label: "sentence similarity",
|
|
11537
|
+
phrases: ["sentence similarity", "semantic similarity"]
|
|
11538
|
+
},
|
|
11539
|
+
{
|
|
11540
|
+
value: "feature-extraction",
|
|
11541
|
+
label: "feature extraction",
|
|
11542
|
+
phrases: ["feature extraction", "embeddings", "embedding"]
|
|
11543
|
+
},
|
|
11544
|
+
{
|
|
11545
|
+
value: "image-classification",
|
|
11546
|
+
label: "image classification",
|
|
11547
|
+
phrases: ["image classification"]
|
|
11548
|
+
},
|
|
11549
|
+
{
|
|
11550
|
+
value: "object-detection",
|
|
11551
|
+
label: "object detection",
|
|
11552
|
+
phrases: ["object detection"]
|
|
11553
|
+
},
|
|
11554
|
+
{
|
|
11555
|
+
value: "image-to-text",
|
|
11556
|
+
label: "image to text",
|
|
11557
|
+
phrases: ["image to text", "image-to-text", "ocr"]
|
|
11558
|
+
},
|
|
11559
|
+
{
|
|
11560
|
+
value: "text-to-image",
|
|
11561
|
+
label: "text to image",
|
|
11562
|
+
phrases: ["text to image", "text-to-image"]
|
|
11563
|
+
},
|
|
11564
|
+
{
|
|
11565
|
+
value: "text-to-speech",
|
|
11566
|
+
label: "text to speech",
|
|
11567
|
+
phrases: ["text to speech", "text-to-speech", "tts"]
|
|
11568
|
+
},
|
|
11569
|
+
{
|
|
11570
|
+
value: "text-generation",
|
|
11571
|
+
label: "text generation",
|
|
11572
|
+
phrases: [
|
|
11573
|
+
"text generation",
|
|
11574
|
+
"text-generation",
|
|
11575
|
+
"llm",
|
|
11576
|
+
"chat model",
|
|
11577
|
+
"chat models",
|
|
11578
|
+
"instruct model",
|
|
11579
|
+
"instruct models"
|
|
11580
|
+
]
|
|
11581
|
+
},
|
|
11582
|
+
{
|
|
11583
|
+
value: "text2text-generation",
|
|
11584
|
+
label: "text2text generation",
|
|
11585
|
+
phrases: [
|
|
11586
|
+
"text2text generation",
|
|
11587
|
+
"text-to-text generation",
|
|
11588
|
+
"text to text generation"
|
|
11589
|
+
]
|
|
11590
|
+
},
|
|
11591
|
+
{
|
|
11592
|
+
value: "summarization",
|
|
11593
|
+
label: "summarization",
|
|
11594
|
+
phrases: ["summarization", "summarize", "summarizer"]
|
|
11595
|
+
},
|
|
11596
|
+
{
|
|
11597
|
+
value: "translation",
|
|
11598
|
+
label: "translation",
|
|
11599
|
+
phrases: ["translation", "translate", "translator"]
|
|
11600
|
+
}
|
|
11601
|
+
];
|
|
11602
|
+
const HUGGING_FACE_MODEL_LIBRARIES = [
|
|
11603
|
+
{ value: "sentence-transformers", label: "sentence-transformers", phrases: ["sentence-transformers"] },
|
|
11604
|
+
{ value: "transformers.js", label: "transformers.js", phrases: ["transformers.js"] },
|
|
11605
|
+
{ value: "transformers", label: "transformers", phrases: ["transformers"] },
|
|
11606
|
+
{ value: "diffusers", label: "diffusers", phrases: ["diffusers"] },
|
|
11607
|
+
{ value: "safetensors", label: "safetensors", phrases: ["safetensors"] },
|
|
11608
|
+
{ value: "pytorch", label: "pytorch", phrases: ["pytorch"] },
|
|
11609
|
+
{ value: "tf", label: "tensorflow", phrases: ["tensorflow", "tf"] },
|
|
11610
|
+
{ value: "jax", label: "jax", phrases: ["jax"] },
|
|
11611
|
+
{ value: "onnx", label: "onnx", phrases: ["onnx"] },
|
|
11612
|
+
{ value: "gguf", label: "gguf", phrases: ["gguf"] },
|
|
11613
|
+
{ value: "mlx", label: "mlx", phrases: ["mlx"] }
|
|
11614
|
+
];
|
|
11615
|
+
function escapeRegex(value) {
|
|
11616
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
11617
|
+
}
|
|
11618
|
+
function stripSearchPhrase(query, phrase) {
|
|
11619
|
+
return query.replace(
|
|
11620
|
+
new RegExp(`(^|[^\\w])${escapeRegex(phrase)}(?=[^\\w]|$)`, "gi"),
|
|
11621
|
+
" "
|
|
11622
|
+
);
|
|
11623
|
+
}
|
|
11624
|
+
function collapseSearchTerms(query) {
|
|
11625
|
+
return query.replace(/\b(on|in|for|with|without|from|by|to|of|the|a|an|and|or)\b/gi, " ").replace(/\b(find|show|search|browse|look(?:ing)?(?:\s+for)?|need|want)\b/gi, " ").replace(/\bhugging\s*face\b/gi, " ").replace(/\s+/g, " ").trim();
|
|
11626
|
+
}
|
|
11627
|
+
function normalizeSearchQuery(query) {
|
|
11628
|
+
return query.replace(/\s+/g, " ").trim();
|
|
11629
|
+
}
|
|
11630
|
+
function extractFirstMatchingFilter(query, filters) {
|
|
11631
|
+
for (const filter of filters) {
|
|
11632
|
+
for (const phrase of filter.phrases) {
|
|
11633
|
+
const pattern = new RegExp(
|
|
11634
|
+
`(^|[^\\w])${escapeRegex(phrase)}(?=[^\\w]|$)`,
|
|
11635
|
+
"i"
|
|
11636
|
+
);
|
|
11637
|
+
if (!pattern.test(query)) continue;
|
|
11638
|
+
return {
|
|
11639
|
+
match: { value: filter.value, label: filter.label },
|
|
11640
|
+
remainingQuery: stripSearchPhrase(query, phrase)
|
|
11641
|
+
};
|
|
11642
|
+
}
|
|
11643
|
+
}
|
|
11644
|
+
return { match: null, remainingQuery: query };
|
|
11645
|
+
}
|
|
11646
|
+
function mapHuggingFaceParameterBucket(query) {
|
|
11647
|
+
const match = query.match(/\b(\d+(?:\.\d+)?)\s*(b|bn|billion|t|tn|trillion)\b/i);
|
|
11648
|
+
if (!match) {
|
|
11649
|
+
return { value: null, label: null, remainingQuery: query };
|
|
11650
|
+
}
|
|
11651
|
+
const amount = Number(match[1]);
|
|
11652
|
+
if (!Number.isFinite(amount) || amount <= 0) {
|
|
11653
|
+
return { value: null, label: null, remainingQuery: query };
|
|
11654
|
+
}
|
|
11655
|
+
const unit = match[2].toLowerCase();
|
|
11656
|
+
const billions = unit === "t" || unit === "tn" || unit === "trillion" ? amount * 1e3 : amount;
|
|
11657
|
+
let value;
|
|
11658
|
+
if (billions < 1) value = "n<1B";
|
|
11659
|
+
else if (billions < 3) value = "1B<n<3B";
|
|
11660
|
+
else if (billions < 6) value = "3B<n<6B";
|
|
11661
|
+
else if (billions < 9) value = "6B<n<9B";
|
|
11662
|
+
else if (billions < 12) value = "9B<n<12B";
|
|
11663
|
+
else if (billions < 24) value = "12B<n<24B";
|
|
11664
|
+
else if (billions < 32) value = "24B<n<32B";
|
|
11665
|
+
else if (billions < 64) value = "32B<n<64B";
|
|
11666
|
+
else if (billions < 128) value = "64B<n<128B";
|
|
11667
|
+
else if (billions < 256) value = "128B<n<256B";
|
|
11668
|
+
else if (billions < 500) value = "256B<n<500B";
|
|
11669
|
+
else if (billions < 1e3) value = "500B<n<1T";
|
|
11670
|
+
else value = "n>1T";
|
|
11671
|
+
return {
|
|
11672
|
+
value,
|
|
11673
|
+
label: `${amount}${unit.startsWith("t") ? "T" : "B"} size bucket`,
|
|
11674
|
+
remainingQuery: query.replace(match[0], " ")
|
|
11675
|
+
};
|
|
11676
|
+
}
|
|
11677
|
+
function chooseHuggingFaceSection(url, query) {
|
|
11678
|
+
const pathname = url.pathname.toLowerCase();
|
|
11679
|
+
const normalized = query.toLowerCase();
|
|
11680
|
+
const mentionsDatasets = /\b(dataset|datasets|corpus|benchmark|benchmarks)\b/.test(
|
|
11681
|
+
normalized
|
|
11682
|
+
);
|
|
11683
|
+
const mentionsSpaces = /\b(space|spaces|app|apps|demo|demos|gradio|streamlit)\b/.test(
|
|
11684
|
+
normalized
|
|
11685
|
+
);
|
|
11686
|
+
const mentionsModels = /\b(model|models|checkpoint|checkpoints|lora|loras|weights)\b/.test(
|
|
11687
|
+
normalized
|
|
11688
|
+
);
|
|
11689
|
+
if (mentionsDatasets && !mentionsModels && !mentionsSpaces) return "datasets";
|
|
11690
|
+
if (mentionsSpaces && !mentionsModels && !mentionsDatasets) return "spaces";
|
|
11691
|
+
if (mentionsModels && !mentionsDatasets && !mentionsSpaces) return "models";
|
|
11692
|
+
if (pathname.startsWith("/models")) return "models";
|
|
11693
|
+
if (pathname.startsWith("/datasets")) return "datasets";
|
|
11694
|
+
if (pathname.startsWith("/spaces")) return "spaces";
|
|
11695
|
+
if (HUGGING_FACE_MODEL_TASKS.some(
|
|
11696
|
+
(entry) => entry.phrases.some(
|
|
11697
|
+
(phrase) => new RegExp(`(^|[^\\w])${escapeRegex(phrase)}(?=[^\\w]|$)`, "i").test(
|
|
11698
|
+
normalized
|
|
11699
|
+
)
|
|
11700
|
+
)
|
|
11701
|
+
) || HUGGING_FACE_MODEL_LIBRARIES.some(
|
|
11702
|
+
(entry) => entry.phrases.some(
|
|
11703
|
+
(phrase) => new RegExp(`(^|[^\\w])${escapeRegex(phrase)}(?=[^\\w]|$)`, "i").test(
|
|
11704
|
+
normalized
|
|
11705
|
+
)
|
|
11706
|
+
)
|
|
11707
|
+
) || /\b\d+(?:\.\d+)?\s*(b|bn|billion|t|tn|trillion)\b/i.test(normalized)) {
|
|
11708
|
+
return "models";
|
|
11709
|
+
}
|
|
11710
|
+
return null;
|
|
11711
|
+
}
|
|
11712
|
+
function buildHuggingFaceSearchShortcut(currentUrl, rawQuery) {
|
|
11713
|
+
let url;
|
|
11714
|
+
try {
|
|
11715
|
+
url = new URL(currentUrl);
|
|
11716
|
+
} catch {
|
|
11717
|
+
return null;
|
|
11718
|
+
}
|
|
11719
|
+
const hostname = url.hostname.toLowerCase();
|
|
11720
|
+
if (!HUGGING_FACE_HUB_HOSTS.has(hostname)) {
|
|
11721
|
+
return null;
|
|
11722
|
+
}
|
|
11723
|
+
const query = rawQuery.trim();
|
|
11724
|
+
if (!query) return null;
|
|
11725
|
+
const section = chooseHuggingFaceSection(url, query);
|
|
11726
|
+
if (!section) return null;
|
|
11727
|
+
let remainingQuery = query;
|
|
11728
|
+
const target = new URL(`https://huggingface.co/${section}`);
|
|
11729
|
+
const appliedFilters = [];
|
|
11730
|
+
if (section === "models") {
|
|
11731
|
+
const taskResult = extractFirstMatchingFilter(
|
|
11732
|
+
remainingQuery,
|
|
11733
|
+
HUGGING_FACE_MODEL_TASKS
|
|
11734
|
+
);
|
|
11735
|
+
remainingQuery = taskResult.remainingQuery;
|
|
11736
|
+
if (taskResult.match) {
|
|
11737
|
+
target.searchParams.append("pipeline_tag", taskResult.match.value);
|
|
11738
|
+
appliedFilters.push(`task: ${taskResult.match.label}`);
|
|
11739
|
+
}
|
|
11740
|
+
const libraryResult = extractFirstMatchingFilter(
|
|
11741
|
+
remainingQuery,
|
|
11742
|
+
HUGGING_FACE_MODEL_LIBRARIES
|
|
11743
|
+
);
|
|
11744
|
+
remainingQuery = libraryResult.remainingQuery;
|
|
11745
|
+
if (libraryResult.match) {
|
|
11746
|
+
target.searchParams.append("library", libraryResult.match.value);
|
|
11747
|
+
appliedFilters.push(`library: ${libraryResult.match.label}`);
|
|
11748
|
+
}
|
|
11749
|
+
const parameterResult = mapHuggingFaceParameterBucket(remainingQuery);
|
|
11750
|
+
remainingQuery = parameterResult.remainingQuery;
|
|
11751
|
+
if (parameterResult.value && parameterResult.label) {
|
|
11752
|
+
target.searchParams.append("num_parameters", parameterResult.value);
|
|
11753
|
+
appliedFilters.push(parameterResult.label);
|
|
11754
|
+
}
|
|
11755
|
+
}
|
|
11756
|
+
remainingQuery = collapseSearchTerms(
|
|
11757
|
+
remainingQuery.replace(/\bmodels?\b/gi, " ").replace(/\bdatasets?\b/gi, " ").replace(/\bspaces?\b/gi, " ").replace(/\bapps?\b/gi, " ")
|
|
11758
|
+
);
|
|
11759
|
+
if (remainingQuery) {
|
|
11760
|
+
target.searchParams.set("search", remainingQuery);
|
|
11761
|
+
}
|
|
11762
|
+
if (!remainingQuery && appliedFilters.length === 0) {
|
|
11763
|
+
return null;
|
|
11764
|
+
}
|
|
11765
|
+
if (section === "spaces" && remainingQuery) {
|
|
11766
|
+
target.searchParams.set("includeNonRunning", "true");
|
|
11767
|
+
}
|
|
11768
|
+
return {
|
|
11769
|
+
url: target.toString(),
|
|
11770
|
+
source: "Hugging Face",
|
|
11771
|
+
section,
|
|
11772
|
+
appliedFilters
|
|
11773
|
+
};
|
|
11774
|
+
}
|
|
11775
|
+
const COMMON_SEARCH_QUERY_PARAMS = [
|
|
11776
|
+
"search",
|
|
11777
|
+
"q",
|
|
11778
|
+
"query",
|
|
11779
|
+
"keyword",
|
|
11780
|
+
"keywords",
|
|
11781
|
+
"term",
|
|
11782
|
+
"text"
|
|
11783
|
+
];
|
|
11784
|
+
const COMMON_PAGINATION_PARAMS = [
|
|
11785
|
+
"p",
|
|
11786
|
+
"page",
|
|
11787
|
+
"offset",
|
|
11788
|
+
"start",
|
|
11789
|
+
"cursor",
|
|
11790
|
+
"skip"
|
|
11791
|
+
];
|
|
11792
|
+
function looksLikeSearchResultsPath(pathname) {
|
|
11793
|
+
return /\/(search|results|browse|discover|find)(\/|$)/i.test(pathname);
|
|
11794
|
+
}
|
|
11795
|
+
function buildCommonSearchUrlShortcut(currentUrl, rawQuery) {
|
|
11796
|
+
let url;
|
|
11797
|
+
try {
|
|
11798
|
+
url = new URL(currentUrl);
|
|
11799
|
+
} catch {
|
|
11800
|
+
return null;
|
|
11801
|
+
}
|
|
11802
|
+
if (!/^https?:$/i.test(url.protocol)) {
|
|
11803
|
+
return null;
|
|
11804
|
+
}
|
|
11805
|
+
const query = normalizeSearchQuery(rawQuery);
|
|
11806
|
+
if (!query) return null;
|
|
11807
|
+
const existingParam = COMMON_SEARCH_QUERY_PARAMS.find(
|
|
11808
|
+
(param) => url.searchParams.has(param)
|
|
11809
|
+
);
|
|
11810
|
+
if (!existingParam && !looksLikeSearchResultsPath(url.pathname)) {
|
|
11811
|
+
return null;
|
|
11812
|
+
}
|
|
11813
|
+
const target = new URL(url.toString());
|
|
11814
|
+
const searchParam = existingParam ?? "q";
|
|
11815
|
+
target.searchParams.set(searchParam, query);
|
|
11816
|
+
for (const param of COMMON_PAGINATION_PARAMS) {
|
|
11817
|
+
target.searchParams.delete(param);
|
|
11818
|
+
}
|
|
11819
|
+
if (target.toString() === url.toString()) {
|
|
11820
|
+
return null;
|
|
11821
|
+
}
|
|
11822
|
+
return {
|
|
11823
|
+
url: target.toString(),
|
|
11824
|
+
source: "page URL",
|
|
11825
|
+
appliedFilters: existingParam ? [`updated ${existingParam} query`] : []
|
|
11826
|
+
};
|
|
11827
|
+
}
|
|
11828
|
+
function buildSearchShortcut(currentUrl, rawQuery) {
|
|
11829
|
+
return buildHuggingFaceSearchShortcut(currentUrl, rawQuery) ?? buildCommonSearchUrlShortcut(currentUrl, rawQuery);
|
|
11830
|
+
}
|
|
11512
11831
|
async function locateSearchTarget(wc, explicitSelector) {
|
|
11513
11832
|
if (explicitSelector) {
|
|
11514
11833
|
return { selector: explicitSelector, submitSelector: null };
|
|
@@ -11775,6 +12094,19 @@ async function searchPage(wc, args) {
|
|
|
11775
12094
|
if (buttonLikePatterns.some((p) => queryLower.includes(p))) {
|
|
11776
12095
|
return `Error: "${query}" looks like a button label, not a search query. Use the click tool to interact with this element instead.`;
|
|
11777
12096
|
}
|
|
12097
|
+
if (typeof args.selector !== "string") {
|
|
12098
|
+
const shortcut = buildSearchShortcut(wc.getURL(), query);
|
|
12099
|
+
if (shortcut) {
|
|
12100
|
+
const beforeUrl2 = wc.getURL();
|
|
12101
|
+
assertSafeURL(shortcut.url);
|
|
12102
|
+
wc.loadURL(shortcut.url);
|
|
12103
|
+
await waitForPotentialNavigation$1(wc, beforeUrl2, 4e3);
|
|
12104
|
+
const afterUrl2 = wc.getURL();
|
|
12105
|
+
const applied = shortcut.appliedFilters.length > 0 ? ` (${shortcut.appliedFilters.join(", ")})` : "";
|
|
12106
|
+
const destination = shortcut.section ? ` ${shortcut.section}` : "";
|
|
12107
|
+
return `Searched "${query}" via ${shortcut.source}${destination} shortcut${applied} → ${afterUrl2}`;
|
|
12108
|
+
}
|
|
12109
|
+
}
|
|
11778
12110
|
const searchInfo = await locateSearchTarget(
|
|
11779
12111
|
wc,
|
|
11780
12112
|
typeof args.selector === "string" ? args.selector : void 0
|
|
@@ -18755,11 +19087,21 @@ function stopMcpServer() {
|
|
|
18755
19087
|
});
|
|
18756
19088
|
});
|
|
18757
19089
|
}
|
|
19090
|
+
const VALID_KIT_CATEGORIES = /* @__PURE__ */ new Set([
|
|
19091
|
+
"research",
|
|
19092
|
+
"shopping",
|
|
19093
|
+
"productivity",
|
|
19094
|
+
"forms"
|
|
19095
|
+
]);
|
|
18758
19096
|
const BUNDLED_KIT_IDS = /* @__PURE__ */ new Set([
|
|
18759
19097
|
"research-collect",
|
|
18760
19098
|
"price-scout",
|
|
18761
19099
|
"form-filler"
|
|
18762
19100
|
]);
|
|
19101
|
+
const KIT_ID_UNSAFE_CHAR_PATTERN = /[\/\\\0]/;
|
|
19102
|
+
function isSafeAutomationKitId(id) {
|
|
19103
|
+
return id.length > 0 && !KIT_ID_UNSAFE_CHAR_PATTERN.test(id);
|
|
19104
|
+
}
|
|
18763
19105
|
function getUserKitsDir() {
|
|
18764
19106
|
return path$1.join(electron.app.getPath("userData"), "kits");
|
|
18765
19107
|
}
|
|
@@ -18769,10 +19111,16 @@ function ensureKitsDir() {
|
|
|
18769
19111
|
fs$1.mkdirSync(dir, { recursive: true });
|
|
18770
19112
|
}
|
|
18771
19113
|
}
|
|
19114
|
+
function getKitFilePath(id) {
|
|
19115
|
+
if (!isSafeAutomationKitId(id)) return null;
|
|
19116
|
+
const kitsDir = path$1.resolve(getUserKitsDir());
|
|
19117
|
+
const target = path$1.resolve(kitsDir, `${id}.kit.json`);
|
|
19118
|
+
return target.startsWith(`${kitsDir}${path$1.sep}`) ? target : null;
|
|
19119
|
+
}
|
|
18772
19120
|
function isValidKit(value) {
|
|
18773
19121
|
if (!value || typeof value !== "object") return false;
|
|
18774
19122
|
const k = value;
|
|
18775
|
-
return typeof k.id === "string" && k.id
|
|
19123
|
+
return typeof k.id === "string" && isSafeAutomationKitId(k.id) && typeof k.name === "string" && k.name.length > 0 && typeof k.description === "string" && typeof k.category === "string" && VALID_KIT_CATEGORIES.has(k.category) && typeof k.icon === "string" && typeof k.promptTemplate === "string" && k.promptTemplate.length > 0 && Array.isArray(k.inputs);
|
|
18776
19124
|
}
|
|
18777
19125
|
function getInstalledKits() {
|
|
18778
19126
|
ensureKitsDir();
|
|
@@ -18833,7 +19181,10 @@ async function installKitFromFile() {
|
|
|
18833
19181
|
};
|
|
18834
19182
|
}
|
|
18835
19183
|
ensureKitsDir();
|
|
18836
|
-
const dest =
|
|
19184
|
+
const dest = getKitFilePath(parsed.id);
|
|
19185
|
+
if (!dest) {
|
|
19186
|
+
return { ok: false, error: "Kit id contains unsupported characters." };
|
|
19187
|
+
}
|
|
18837
19188
|
try {
|
|
18838
19189
|
fs$1.writeFileSync(dest, JSON.stringify(parsed, null, 2), "utf-8");
|
|
18839
19190
|
} catch {
|
|
@@ -18841,12 +19192,21 @@ async function installKitFromFile() {
|
|
|
18841
19192
|
}
|
|
18842
19193
|
return { ok: true, kit: parsed };
|
|
18843
19194
|
}
|
|
18844
|
-
function uninstallKit(id) {
|
|
19195
|
+
function uninstallKit(id, scheduledKitIds) {
|
|
18845
19196
|
if (BUNDLED_KIT_IDS.has(id)) {
|
|
18846
19197
|
return { ok: false, error: "Built-in kits cannot be removed." };
|
|
18847
19198
|
}
|
|
19199
|
+
if (scheduledKitIds?.has(id)) {
|
|
19200
|
+
return {
|
|
19201
|
+
ok: false,
|
|
19202
|
+
error: "This kit has active scheduled jobs. Delete or reassign them first."
|
|
19203
|
+
};
|
|
19204
|
+
}
|
|
18848
19205
|
ensureKitsDir();
|
|
18849
|
-
const target =
|
|
19206
|
+
const target = getKitFilePath(id);
|
|
19207
|
+
if (!target) {
|
|
19208
|
+
return { ok: false, error: "Kit id contains unsupported characters." };
|
|
19209
|
+
}
|
|
18850
19210
|
if (!fs$1.existsSync(target)) {
|
|
18851
19211
|
return { ok: false, error: "Kit not found." };
|
|
18852
19212
|
}
|
|
@@ -18860,6 +19220,9 @@ function uninstallKit(id) {
|
|
|
18860
19220
|
let jobs = [];
|
|
18861
19221
|
let removeIdleListener = null;
|
|
18862
19222
|
let broadcastFn = null;
|
|
19223
|
+
function getScheduledKitIds() {
|
|
19224
|
+
return new Set(jobs.filter((j) => j.enabled).map((j) => j.kitId));
|
|
19225
|
+
}
|
|
18863
19226
|
function getJobsPath() {
|
|
18864
19227
|
return path$1.join(electron.app.getPath("userData"), "scheduled-jobs.json");
|
|
18865
19228
|
}
|
|
@@ -19029,29 +19392,40 @@ async function fireJob(job, windowState, runtime2) {
|
|
|
19029
19392
|
}
|
|
19030
19393
|
function tick(windowState, runtime2) {
|
|
19031
19394
|
if (isAIStreamActive()) return;
|
|
19032
|
-
const
|
|
19033
|
-
|
|
19034
|
-
|
|
19035
|
-
|
|
19036
|
-
|
|
19037
|
-
if (
|
|
19038
|
-
void fireJob(job, windowState, runtime2).finally(() => {
|
|
19395
|
+
const dueIds = jobs.filter((job) => job.enabled && /* @__PURE__ */ new Date() >= new Date(job.nextRunAt)).map((job) => job.id);
|
|
19396
|
+
if (dueIds.length === 0) return;
|
|
19397
|
+
if (!tryBeginAIStream("scheduled")) return;
|
|
19398
|
+
let idx = 0;
|
|
19399
|
+
const fireNext = () => {
|
|
19400
|
+
if (idx >= dueIds.length) {
|
|
19039
19401
|
endAIStream("scheduled");
|
|
19040
19402
|
queueMicrotask(() => tick(windowState, runtime2));
|
|
19041
|
-
|
|
19042
|
-
|
|
19403
|
+
return;
|
|
19404
|
+
}
|
|
19405
|
+
const jobId = dueIds[idx++];
|
|
19406
|
+
const job = jobs.find((candidate) => candidate.id === jobId);
|
|
19407
|
+
if (!job || !job.enabled) {
|
|
19408
|
+
fireNext();
|
|
19409
|
+
return;
|
|
19410
|
+
}
|
|
19411
|
+
const firedAt = /* @__PURE__ */ new Date();
|
|
19412
|
+
if (firedAt < new Date(job.nextRunAt)) {
|
|
19413
|
+
fireNext();
|
|
19414
|
+
return;
|
|
19415
|
+
}
|
|
19416
|
+
job.lastRunAt = firedAt.toISOString();
|
|
19043
19417
|
if (job.schedule.type === "once") {
|
|
19044
19418
|
job.enabled = false;
|
|
19045
19419
|
} else {
|
|
19046
|
-
job.nextRunAt = computeNextRun(job.schedule,
|
|
19420
|
+
job.nextRunAt = computeNextRun(job.schedule, firedAt).toISOString();
|
|
19047
19421
|
}
|
|
19048
|
-
changed = true;
|
|
19049
|
-
break;
|
|
19050
|
-
}
|
|
19051
|
-
if (changed) {
|
|
19052
19422
|
saveJobs();
|
|
19053
19423
|
broadcastFn?.(Channels.SCHEDULE_JOBS_UPDATE, jobs);
|
|
19054
|
-
|
|
19424
|
+
void fireJob(job, windowState, runtime2).catch((err) => {
|
|
19425
|
+
console.warn("[scheduler] Unexpected error firing job:", err);
|
|
19426
|
+
}).finally(fireNext);
|
|
19427
|
+
};
|
|
19428
|
+
fireNext();
|
|
19055
19429
|
}
|
|
19056
19430
|
function registerScheduleHandlers(windowState, runtime2, sendToAll) {
|
|
19057
19431
|
broadcastFn = sendToAll;
|
|
@@ -19314,7 +19688,7 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
19314
19688
|
Channels.AI_STREAM_CHUNK,
|
|
19315
19689
|
"Chat provider not configured. Open Settings (Ctrl+,) to choose a provider."
|
|
19316
19690
|
);
|
|
19317
|
-
sendToRendererViews(Channels.AI_STREAM_END);
|
|
19691
|
+
sendToRendererViews(Channels.AI_STREAM_END, "failed");
|
|
19318
19692
|
return { accepted: true };
|
|
19319
19693
|
}
|
|
19320
19694
|
if (!tryBeginAIStream("manual")) {
|
|
@@ -19331,7 +19705,7 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
19331
19705
|
activeChatProvider,
|
|
19332
19706
|
activeTab?.view.webContents,
|
|
19333
19707
|
(chunk) => sendToRendererViews(Channels.AI_STREAM_CHUNK, chunk),
|
|
19334
|
-
() => sendToRendererViews(Channels.AI_STREAM_END),
|
|
19708
|
+
() => sendToRendererViews(Channels.AI_STREAM_END, "completed"),
|
|
19335
19709
|
tabManager,
|
|
19336
19710
|
runtime2,
|
|
19337
19711
|
history
|
|
@@ -19340,7 +19714,7 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
19340
19714
|
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
19341
19715
|
sendToRendererViews(Channels.AI_STREAM_CHUNK, `
|
|
19342
19716
|
[Error: ${msg}]`);
|
|
19343
|
-
sendToRendererViews(Channels.AI_STREAM_END);
|
|
19717
|
+
sendToRendererViews(Channels.AI_STREAM_END, "failed");
|
|
19344
19718
|
} finally {
|
|
19345
19719
|
activeChatProvider = null;
|
|
19346
19720
|
endAIStream("manual");
|
|
@@ -19762,7 +20136,7 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
19762
20136
|
});
|
|
19763
20137
|
electron.ipcMain.handle(Channels.AUTOMATION_UNINSTALL, (_event, id) => {
|
|
19764
20138
|
assertString(id, "id");
|
|
19765
|
-
return uninstallKit(id);
|
|
20139
|
+
return uninstallKit(id, getScheduledKitIds());
|
|
19766
20140
|
});
|
|
19767
20141
|
registerScheduleHandlers(windowState, runtime2, sendToRendererViews);
|
|
19768
20142
|
}
|
package/out/preload/index.js
CHANGED
|
@@ -137,7 +137,7 @@ const api = {
|
|
|
137
137
|
return () => electron.ipcRenderer.removeListener(Channels.AI_STREAM_CHUNK, handler);
|
|
138
138
|
},
|
|
139
139
|
onStreamEnd: (cb) => {
|
|
140
|
-
const handler = () => cb();
|
|
140
|
+
const handler = (_, status = "completed") => cb(status);
|
|
141
141
|
electron.ipcRenderer.on(Channels.AI_STREAM_END, handler);
|
|
142
142
|
return () => electron.ipcRenderer.removeListener(Channels.AI_STREAM_END, handler);
|
|
143
143
|
},
|
|
@@ -2324,11 +2324,14 @@ const [hasFirstChunk, setHasFirstChunk] = createSignal(false);
|
|
|
2324
2324
|
const [streamStartedAt, setStreamStartedAt] = createSignal(null);
|
|
2325
2325
|
const [recentQueries, setRecentQueries] = createSignal([]);
|
|
2326
2326
|
const [pendingQueries, setPendingQueries] = createSignal([]);
|
|
2327
|
+
const [pendingQueryActivities, setPendingQueryActivities] = createSignal([]);
|
|
2327
2328
|
const [queueNotice, setQueueNotice] = createSignal(null);
|
|
2328
2329
|
const [automationActivities, setAutomationActivities] = createSignal([]);
|
|
2329
2330
|
let initialized$1 = false;
|
|
2330
2331
|
let pendingDrainScheduled = false;
|
|
2331
2332
|
let listenerCleanups = [];
|
|
2333
|
+
let pendingAutomationActivity = null;
|
|
2334
|
+
let activeAutomationActivityId = null;
|
|
2332
2335
|
function trimMessages(next) {
|
|
2333
2336
|
return next.length > MAX_MESSAGE_HISTORY ? next.slice(-MAX_MESSAGE_HISTORY) : next;
|
|
2334
2337
|
}
|
|
@@ -2348,17 +2351,23 @@ async function dispatchQuery(prompt) {
|
|
|
2348
2351
|
const result = await window.vessel.ai.query(prompt, buildHistory());
|
|
2349
2352
|
return result.accepted;
|
|
2350
2353
|
}
|
|
2351
|
-
async function dispatchQueuedPrompt(prompt) {
|
|
2354
|
+
async function dispatchQueuedPrompt(prompt, activity) {
|
|
2355
|
+
pendingAutomationActivity = activity;
|
|
2352
2356
|
const accepted = await dispatchQuery(prompt);
|
|
2353
2357
|
if (!accepted) {
|
|
2358
|
+
pendingAutomationActivity = null;
|
|
2354
2359
|
const queued = enqueuePendingPrompt(pendingQueries(), prompt, { atFront: true });
|
|
2355
2360
|
setPendingQueries(queued.queue);
|
|
2356
2361
|
setQueueNotice(queued.notice);
|
|
2362
|
+
if (queued.status === "queued") {
|
|
2363
|
+
setPendingQueryActivities((prev) => [activity, ...prev]);
|
|
2364
|
+
}
|
|
2357
2365
|
}
|
|
2358
2366
|
}
|
|
2359
2367
|
function schedulePendingDrain() {
|
|
2360
2368
|
if (pendingDrainScheduled || isStreaming()) return;
|
|
2361
2369
|
if (pendingQueries().length === 0) {
|
|
2370
|
+
setPendingQueryActivities([]);
|
|
2362
2371
|
setQueueNotice(null);
|
|
2363
2372
|
return;
|
|
2364
2373
|
}
|
|
@@ -2367,10 +2376,12 @@ function schedulePendingDrain() {
|
|
|
2367
2376
|
pendingDrainScheduled = false;
|
|
2368
2377
|
if (isStreaming()) return;
|
|
2369
2378
|
const next = dequeuePendingPrompt(pendingQueries());
|
|
2379
|
+
const [nextActivity = null, ...remainingActivities] = pendingQueryActivities();
|
|
2370
2380
|
setPendingQueries(next.queue);
|
|
2381
|
+
setPendingQueryActivities(remainingActivities);
|
|
2371
2382
|
setQueueNotice(next.notice);
|
|
2372
2383
|
if (next.nextPrompt) {
|
|
2373
|
-
void dispatchQueuedPrompt(next.nextPrompt);
|
|
2384
|
+
void dispatchQueuedPrompt(next.nextPrompt, nextActivity);
|
|
2374
2385
|
}
|
|
2375
2386
|
});
|
|
2376
2387
|
}
|
|
@@ -2386,14 +2397,35 @@ function init$1() {
|
|
|
2386
2397
|
setIsStreaming(true);
|
|
2387
2398
|
setHasFirstChunk(false);
|
|
2388
2399
|
setStreamStartedAt(Date.now());
|
|
2400
|
+
if (pendingAutomationActivity) {
|
|
2401
|
+
const activity = pendingAutomationActivity;
|
|
2402
|
+
activeAutomationActivityId = activity.id;
|
|
2403
|
+
setAutomationActivities(
|
|
2404
|
+
(prev) => startAutomationActivity(prev, {
|
|
2405
|
+
id: activity.id,
|
|
2406
|
+
source: "scheduled",
|
|
2407
|
+
title: activity.title,
|
|
2408
|
+
icon: activity.icon,
|
|
2409
|
+
status: "running",
|
|
2410
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2411
|
+
})
|
|
2412
|
+
);
|
|
2413
|
+
pendingAutomationActivity = null;
|
|
2414
|
+
}
|
|
2389
2415
|
}));
|
|
2390
2416
|
listenerCleanups.push(window.vessel.ai.onStreamChunk((chunk) => {
|
|
2391
2417
|
if (!hasFirstChunk()) {
|
|
2392
2418
|
setHasFirstChunk(true);
|
|
2393
2419
|
}
|
|
2394
2420
|
setStreamingText((prev) => prev + chunk);
|
|
2421
|
+
if (activeAutomationActivityId) {
|
|
2422
|
+
const activityId = activeAutomationActivityId;
|
|
2423
|
+
setAutomationActivities(
|
|
2424
|
+
(prev) => appendAutomationActivityChunk(prev, activityId, chunk)
|
|
2425
|
+
);
|
|
2426
|
+
}
|
|
2395
2427
|
}));
|
|
2396
|
-
listenerCleanups.push(window.vessel.ai.onStreamEnd(() => {
|
|
2428
|
+
listenerCleanups.push(window.vessel.ai.onStreamEnd((status) => {
|
|
2397
2429
|
const finalText = streamingText();
|
|
2398
2430
|
if (finalText) {
|
|
2399
2431
|
setMessages((prev) => {
|
|
@@ -2401,6 +2433,19 @@ function init$1() {
|
|
|
2401
2433
|
return trimMessages(next);
|
|
2402
2434
|
});
|
|
2403
2435
|
}
|
|
2436
|
+
if (activeAutomationActivityId) {
|
|
2437
|
+
const activityId = activeAutomationActivityId;
|
|
2438
|
+
setAutomationActivities(
|
|
2439
|
+
(prev) => finishAutomationActivity(
|
|
2440
|
+
prev,
|
|
2441
|
+
activityId,
|
|
2442
|
+
status,
|
|
2443
|
+
(/* @__PURE__ */ new Date()).toISOString()
|
|
2444
|
+
)
|
|
2445
|
+
);
|
|
2446
|
+
activeAutomationActivityId = null;
|
|
2447
|
+
}
|
|
2448
|
+
pendingAutomationActivity = null;
|
|
2404
2449
|
setStreamingText("");
|
|
2405
2450
|
setIsStreaming(false);
|
|
2406
2451
|
setHasFirstChunk(false);
|
|
@@ -2426,6 +2471,32 @@ function init$1() {
|
|
|
2426
2471
|
}
|
|
2427
2472
|
function useAI() {
|
|
2428
2473
|
init$1();
|
|
2474
|
+
const query = async (prompt, activity = null) => {
|
|
2475
|
+
recordRecentQuery(prompt);
|
|
2476
|
+
if (isStreaming()) {
|
|
2477
|
+
const queued = enqueuePendingPrompt(pendingQueries(), prompt);
|
|
2478
|
+
setPendingQueries(queued.queue);
|
|
2479
|
+
setQueueNotice(queued.notice);
|
|
2480
|
+
if (queued.status === "queued") {
|
|
2481
|
+
setPendingQueryActivities((prev) => [...prev, activity]);
|
|
2482
|
+
}
|
|
2483
|
+
return queued.status;
|
|
2484
|
+
}
|
|
2485
|
+
setQueueNotice(null);
|
|
2486
|
+
pendingAutomationActivity = activity;
|
|
2487
|
+
const accepted = await dispatchQuery(prompt);
|
|
2488
|
+
if (!accepted) {
|
|
2489
|
+
pendingAutomationActivity = null;
|
|
2490
|
+
const queued = enqueuePendingPrompt(pendingQueries(), prompt, { atFront: true });
|
|
2491
|
+
setPendingQueries(queued.queue);
|
|
2492
|
+
setQueueNotice(queued.notice);
|
|
2493
|
+
if (queued.status === "queued") {
|
|
2494
|
+
setPendingQueryActivities((prev) => [activity, ...prev]);
|
|
2495
|
+
}
|
|
2496
|
+
return queued.status;
|
|
2497
|
+
}
|
|
2498
|
+
return "started";
|
|
2499
|
+
};
|
|
2429
2500
|
return {
|
|
2430
2501
|
messages,
|
|
2431
2502
|
streamingText,
|
|
@@ -2438,39 +2509,28 @@ function useAI() {
|
|
|
2438
2509
|
pendingQueryCount: () => pendingQueries().length,
|
|
2439
2510
|
pendingQueryLimit: MAX_PENDING_QUERIES,
|
|
2440
2511
|
queueNotice,
|
|
2441
|
-
query
|
|
2442
|
-
|
|
2443
|
-
if (isStreaming()) {
|
|
2444
|
-
const queued = enqueuePendingPrompt(pendingQueries(), prompt);
|
|
2445
|
-
setPendingQueries(queued.queue);
|
|
2446
|
-
setQueueNotice(queued.notice);
|
|
2447
|
-
return queued.status;
|
|
2448
|
-
}
|
|
2449
|
-
setQueueNotice(null);
|
|
2450
|
-
const accepted = await dispatchQuery(prompt);
|
|
2451
|
-
if (!accepted) {
|
|
2452
|
-
const queued = enqueuePendingPrompt(pendingQueries(), prompt, { atFront: true });
|
|
2453
|
-
setPendingQueries(queued.queue);
|
|
2454
|
-
setQueueNotice(queued.notice);
|
|
2455
|
-
return queued.status;
|
|
2456
|
-
}
|
|
2457
|
-
return "started";
|
|
2458
|
-
},
|
|
2512
|
+
query,
|
|
2513
|
+
runAutomationPrompt: async (prompt, activity) => query(prompt, activity),
|
|
2459
2514
|
cancel: () => window.vessel.ai.cancel(),
|
|
2460
2515
|
removePendingQuery: (index) => {
|
|
2461
2516
|
const next = removePendingPrompt(pendingQueries(), index);
|
|
2462
2517
|
setPendingQueries(next.queue);
|
|
2518
|
+
setPendingQueryActivities(
|
|
2519
|
+
(prev) => prev.filter((_, itemIndex) => itemIndex !== index)
|
|
2520
|
+
);
|
|
2463
2521
|
setQueueNotice(next.notice);
|
|
2464
2522
|
},
|
|
2465
2523
|
clearPendingQueries: () => {
|
|
2466
2524
|
const next = clearPendingPromptQueue();
|
|
2467
2525
|
setPendingQueries(next.queue);
|
|
2526
|
+
setPendingQueryActivities([]);
|
|
2468
2527
|
setQueueNotice(next.notice);
|
|
2469
2528
|
},
|
|
2470
2529
|
clearHistory: () => {
|
|
2471
2530
|
setMessages([]);
|
|
2472
2531
|
const next = clearPendingPromptQueue();
|
|
2473
2532
|
setPendingQueries(next.queue);
|
|
2533
|
+
setPendingQueryActivities([]);
|
|
2474
2534
|
setQueueNotice(next.notice);
|
|
2475
2535
|
}
|
|
2476
2536
|
};
|
|
@@ -4440,6 +4500,11 @@ var Zap = (props) => createComponent(Icon_default, mergeProps(props, {
|
|
|
4440
4500
|
name: "zap"
|
|
4441
4501
|
}));
|
|
4442
4502
|
var zap_default = Zap;
|
|
4503
|
+
const BUNDLED_KIT_IDS = /* @__PURE__ */ new Set([
|
|
4504
|
+
"research-collect",
|
|
4505
|
+
"price-scout",
|
|
4506
|
+
"form-filler"
|
|
4507
|
+
]);
|
|
4443
4508
|
const BUNDLED_KITS = [
|
|
4444
4509
|
{
|
|
4445
4510
|
id: "research-collect",
|
|
@@ -4571,6 +4636,13 @@ Steps:
|
|
|
4571
4636
|
}
|
|
4572
4637
|
];
|
|
4573
4638
|
function renderKitPrompt(kit, values) {
|
|
4639
|
+
for (const input of kit.inputs) {
|
|
4640
|
+
if (input.required && !values[input.key]?.trim()) {
|
|
4641
|
+
console.warn(
|
|
4642
|
+
`[automation-kits] Required field "${input.key}" is empty for kit "${kit.id}".`
|
|
4643
|
+
);
|
|
4644
|
+
}
|
|
4645
|
+
}
|
|
4574
4646
|
return kit.promptTemplate.replace(
|
|
4575
4647
|
/\{\{(\w+)\}\}/g,
|
|
4576
4648
|
(_, key) => values[key] ?? ""
|
|
@@ -4599,7 +4671,6 @@ const KitIcon = (props) => {
|
|
|
4599
4671
|
}
|
|
4600
4672
|
});
|
|
4601
4673
|
};
|
|
4602
|
-
const BUNDLED_KIT_IDS = new Set(BUNDLED_KITS.map((k) => k.id));
|
|
4603
4674
|
const DAY_NAMES = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
|
4604
4675
|
function formatScheduleLabel(job) {
|
|
4605
4676
|
const {
|
|
@@ -4650,7 +4721,7 @@ function toLocalDateTimeInput(iso) {
|
|
|
4650
4721
|
}
|
|
4651
4722
|
const AutomationTab = (props) => {
|
|
4652
4723
|
const {
|
|
4653
|
-
|
|
4724
|
+
runAutomationPrompt,
|
|
4654
4725
|
isStreaming: isStreaming2,
|
|
4655
4726
|
automationActivities: automationActivities2
|
|
4656
4727
|
} = useAI();
|
|
@@ -4739,9 +4810,15 @@ const AutomationTab = (props) => {
|
|
|
4739
4810
|
const kit = selectedKit();
|
|
4740
4811
|
if (!kit || !canRun()) return;
|
|
4741
4812
|
const prompt = renderKitPrompt(kit, fieldValues());
|
|
4813
|
+
const activityId = `adhoc:${kit.id}:${Date.now()}`;
|
|
4814
|
+
const result = await runAutomationPrompt(prompt, {
|
|
4815
|
+
id: activityId,
|
|
4816
|
+
title: kit.name,
|
|
4817
|
+
icon: kit.icon
|
|
4818
|
+
});
|
|
4819
|
+
if (result === "rejected") return;
|
|
4742
4820
|
setSelectedKit(null);
|
|
4743
4821
|
props.onRun();
|
|
4744
|
-
await query(prompt);
|
|
4745
4822
|
};
|
|
4746
4823
|
const handleSchedule = async () => {
|
|
4747
4824
|
const kit = selectedKit();
|
package/out/renderer/index.html
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; font-src 'self' data:;" />
|
|
7
7
|
<title>Vessel</title>
|
|
8
|
-
<script type="module" crossorigin src="./assets/index-
|
|
8
|
+
<script type="module" crossorigin src="./assets/index-BFdOm6Op.js"></script>
|
|
9
9
|
<link rel="stylesheet" crossorigin href="./assets/index-eS3ccAls.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quanta-intellect/vessel-browser",
|
|
3
3
|
"mcpName": "io.github.unmodeled-tyler/vessel-browser",
|
|
4
|
-
"version": "0.1.
|
|
5
|
-
"description": "AI-native web browser
|
|
4
|
+
"version": "0.1.33",
|
|
5
|
+
"description": "AI-native web browser runtime for autonomous agents with human supervision",
|
|
6
6
|
"main": "./out/main/index.js",
|
|
7
7
|
"bin": {
|
|
8
8
|
"vessel-browser": "./bin/vessel-browser.js"
|
|
@@ -18,8 +18,13 @@
|
|
|
18
18
|
"scripts": {
|
|
19
19
|
"dev": "ELECTRON_DISABLE_SANDBOX=1 electron-vite dev",
|
|
20
20
|
"build": "electron-vite build",
|
|
21
|
+
"build:icon:mac": "scripts/build-macos-icon.sh",
|
|
21
22
|
"dist": "npm run build && electron-builder --linux --publish never",
|
|
22
23
|
"dist:dir": "npm run build && electron-builder --linux dir --publish never",
|
|
24
|
+
"dist:mac": "npm run build:icon:mac && npm run build && CSC_IDENTITY_AUTO_DISCOVERY=false electron-builder --mac dmg zip --publish never",
|
|
25
|
+
"dist:mac:dir": "npm run build:icon:mac && npm run build && CSC_IDENTITY_AUTO_DISCOVERY=false electron-builder --mac dir --publish never",
|
|
26
|
+
"dist:mac:signed": "npm run build:icon:mac && npm run build && electron-builder --mac dmg zip --publish never",
|
|
27
|
+
"dist:mac:dir:signed": "npm run build:icon:mac && npm run build && electron-builder --mac dir --publish never",
|
|
23
28
|
"preview": "electron-vite preview",
|
|
24
29
|
"typecheck": "tsc --noEmit",
|
|
25
30
|
"prepublishOnly": "npm run build",
|