@quanta-intellect/vessel-browser 0.1.138 → 0.1.141
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 +13922 -12445
- package/out/preload/content-script.js +76 -4
- package/out/renderer/assets/{index-DMcjRzqj.css → index-T8vlGvDJ.css} +11 -0
- package/out/renderer/assets/{index-Cjl9fej2.js → index-l3uzsLbO.js} +15 -8
- package/out/renderer/index.html +2 -2
- package/package.json +2 -2
|
@@ -2195,6 +2195,7 @@ let pageDiffActivityThrottleTimer = null;
|
|
|
2195
2195
|
let lastPageDiffSignature = "";
|
|
2196
2196
|
const PAGE_DIFF_ACTIVITY_THROTTLE_MS = 350;
|
|
2197
2197
|
const PAGE_DIFF_MUTATION_DEBOUNCE_MS = 1200;
|
|
2198
|
+
const CUSTOM_TEXT_FIELD_SELECTOR = '[contenteditable="true"], [role="textbox"], [role="searchbox"], [role="combobox"]';
|
|
2198
2199
|
function normalizeSignatureText(value) {
|
|
2199
2200
|
return (value || "").replace(/\s+/g, " ").trim();
|
|
2200
2201
|
}
|
|
@@ -2938,6 +2939,37 @@ function getInputLabelWithSource(el) {
|
|
|
2938
2939
|
if (placeholder) return { label: placeholder, source: "placeholder" };
|
|
2939
2940
|
return {};
|
|
2940
2941
|
}
|
|
2942
|
+
function getCustomTextFieldLabelWithSource(el) {
|
|
2943
|
+
const ariaLabel = getTrimmedText(el.getAttribute("aria-label"));
|
|
2944
|
+
if (ariaLabel) return { label: ariaLabel, source: "aria-label" };
|
|
2945
|
+
const labelledBy = getNodeTextByIds(el.getAttribute("aria-labelledby"));
|
|
2946
|
+
if (labelledBy) return { label: labelledBy, source: "label" };
|
|
2947
|
+
const placeholder = getTrimmedText(el.getAttribute("placeholder"));
|
|
2948
|
+
if (placeholder) return { label: placeholder, source: "placeholder" };
|
|
2949
|
+
const text = getTrimmedText(el.textContent);
|
|
2950
|
+
if (text) return { label: text, source: "text" };
|
|
2951
|
+
return {};
|
|
2952
|
+
}
|
|
2953
|
+
function isNativeFormField(el) {
|
|
2954
|
+
return el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement;
|
|
2955
|
+
}
|
|
2956
|
+
function shouldExposeCustomTextField(el) {
|
|
2957
|
+
if (!(el instanceof HTMLElement) || isNativeFormField(el)) return false;
|
|
2958
|
+
if (!isElementVisible(el) || isElementDisabled(el)) return false;
|
|
2959
|
+
const role = getElementRole(el);
|
|
2960
|
+
return el.isContentEditable || el.getAttribute("contenteditable") === "true" || role === "textbox" || role === "searchbox" || role === "combobox";
|
|
2961
|
+
}
|
|
2962
|
+
function getCustomTextFieldInputType(el) {
|
|
2963
|
+
const role = getElementRole(el);
|
|
2964
|
+
if (role === "searchbox") return "search";
|
|
2965
|
+
if (role === "combobox") return "combobox";
|
|
2966
|
+
if (role === "textbox") return "text";
|
|
2967
|
+
return el.getAttribute("contenteditable") === "true" ? "text" : void 0;
|
|
2968
|
+
}
|
|
2969
|
+
function getCustomTextFieldHasValue(el) {
|
|
2970
|
+
const value = getTrimmedText(el.textContent) || getTrimmedText(el.getAttribute("aria-valuetext")) || getTrimmedText(el.getAttribute("value"));
|
|
2971
|
+
return value ? true : void 0;
|
|
2972
|
+
}
|
|
2941
2973
|
function getButtonTextWithSource(el) {
|
|
2942
2974
|
const textContent = getTrimmedText(el.textContent);
|
|
2943
2975
|
if (textContent) return { text: textContent, source: "text" };
|
|
@@ -2986,6 +3018,18 @@ function getElementValue(el) {
|
|
|
2986
3018
|
}
|
|
2987
3019
|
return void 0;
|
|
2988
3020
|
}
|
|
3021
|
+
function getElementHasValue(el) {
|
|
3022
|
+
if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) {
|
|
3023
|
+
if (el.type === "password" || el.type === "checkbox" || el.type === "radio") {
|
|
3024
|
+
return void 0;
|
|
3025
|
+
}
|
|
3026
|
+
return getTrimmedText(el.value) ? true : void 0;
|
|
3027
|
+
}
|
|
3028
|
+
if (el instanceof HTMLSelectElement) {
|
|
3029
|
+
return getTrimmedText(el.value) ? true : void 0;
|
|
3030
|
+
}
|
|
3031
|
+
return void 0;
|
|
3032
|
+
}
|
|
2989
3033
|
function getSelectOptions(el) {
|
|
2990
3034
|
const options = Array.from(el.options).map((option) => ({
|
|
2991
3035
|
label: option.textContent?.trim() || option.value.trim(),
|
|
@@ -2999,6 +3043,13 @@ function getAriaBoolean(el, attr) {
|
|
|
2999
3043
|
if (val === "false") return false;
|
|
3000
3044
|
return void 0;
|
|
3001
3045
|
}
|
|
3046
|
+
function getDeepActiveElement() {
|
|
3047
|
+
let active = document.activeElement;
|
|
3048
|
+
while (active instanceof HTMLElement && active.shadowRoot?.activeElement) {
|
|
3049
|
+
active = active.shadowRoot.activeElement;
|
|
3050
|
+
}
|
|
3051
|
+
return active;
|
|
3052
|
+
}
|
|
3002
3053
|
function buildBaseMetadata(el) {
|
|
3003
3054
|
return {
|
|
3004
3055
|
context: getElementContext(el),
|
|
@@ -3009,6 +3060,7 @@ function buildBaseMetadata(el) {
|
|
|
3009
3060
|
description: getElementDescription(el),
|
|
3010
3061
|
...getVisibilityState(el),
|
|
3011
3062
|
disabled: isElementDisabled(el),
|
|
3063
|
+
focused: getDeepActiveElement() === el || void 0,
|
|
3012
3064
|
ariaExpanded: getAriaBoolean(el, "aria-expanded"),
|
|
3013
3065
|
ariaPressed: getAriaBoolean(el, "aria-pressed"),
|
|
3014
3066
|
ariaSelected: getAriaBoolean(el, "aria-selected")
|
|
@@ -3120,6 +3172,7 @@ function extractInteractiveElements() {
|
|
|
3120
3172
|
placeholder: element.getAttribute("placeholder") || void 0,
|
|
3121
3173
|
required: element.hasAttribute("required") || void 0,
|
|
3122
3174
|
value: getElementValue(element),
|
|
3175
|
+
hasValue: getElementHasValue(element),
|
|
3123
3176
|
options: element instanceof HTMLSelectElement ? getSelectOptions(element) : void 0,
|
|
3124
3177
|
...buildBaseMetadata(input),
|
|
3125
3178
|
role,
|
|
@@ -3128,6 +3181,20 @@ function extractInteractiveElements() {
|
|
|
3128
3181
|
...getFieldMetadata(element)
|
|
3129
3182
|
});
|
|
3130
3183
|
});
|
|
3184
|
+
deepQuerySelectorAll(CUSTOM_TEXT_FIELD_SELECTOR).forEach((field) => {
|
|
3185
|
+
if (!shouldExposeCustomTextField(field)) return;
|
|
3186
|
+
const label = getCustomTextFieldLabelWithSource(field);
|
|
3187
|
+
const role = getElementRole(field);
|
|
3188
|
+
elements.push({
|
|
3189
|
+
type: "input",
|
|
3190
|
+
label: label.label?.slice(0, MAX_LABEL_LENGTH),
|
|
3191
|
+
labelSource: label.source,
|
|
3192
|
+
inputType: getCustomTextFieldInputType(field),
|
|
3193
|
+
hasValue: getCustomTextFieldHasValue(field),
|
|
3194
|
+
...buildBaseMetadata(field),
|
|
3195
|
+
role
|
|
3196
|
+
});
|
|
3197
|
+
});
|
|
3131
3198
|
return elements;
|
|
3132
3199
|
}
|
|
3133
3200
|
function extractForms() {
|
|
@@ -3143,23 +3210,28 @@ function extractForms() {
|
|
|
3143
3210
|
const form = formEl;
|
|
3144
3211
|
const fields = [];
|
|
3145
3212
|
form.querySelectorAll(
|
|
3146
|
-
|
|
3213
|
+
`input:not([type='hidden']):not([type='submit']):not([type='button']):not([type='image']), select, textarea, ${CUSTOM_TEXT_FIELD_SELECTOR}`
|
|
3147
3214
|
).forEach((input) => {
|
|
3215
|
+
if (!isNativeFormField(input) && !shouldExposeCustomTextField(input)) {
|
|
3216
|
+
return;
|
|
3217
|
+
}
|
|
3148
3218
|
const element = input;
|
|
3149
3219
|
const tag = input.tagName.toLowerCase();
|
|
3150
3220
|
const label = getInputLabelWithSource(element);
|
|
3221
|
+
const customLabel = isNativeFormField(input) ? {} : getCustomTextFieldLabelWithSource(input);
|
|
3151
3222
|
const role = getElementRole(input);
|
|
3152
3223
|
const radioText = role === "radio" || element instanceof HTMLInputElement && element.type === "radio" ? getTrimmedText(
|
|
3153
3224
|
element.getAttribute("value") || element.getAttribute("aria-label") || label.label
|
|
3154
3225
|
) : void 0;
|
|
3155
3226
|
fields.push({
|
|
3156
3227
|
type: tag === "select" ? "select" : tag === "textarea" ? "textarea" : "input",
|
|
3157
|
-
label: label.label?.slice(0, MAX_LABEL_LENGTH),
|
|
3158
|
-
labelSource: label.source,
|
|
3159
|
-
inputType: element.getAttribute("type") || void 0,
|
|
3228
|
+
label: (label.label || customLabel.label)?.slice(0, MAX_LABEL_LENGTH),
|
|
3229
|
+
labelSource: label.source || customLabel.source,
|
|
3230
|
+
inputType: element.getAttribute("type") || getCustomTextFieldInputType(input) || void 0,
|
|
3160
3231
|
placeholder: element.getAttribute("placeholder") || void 0,
|
|
3161
3232
|
required: element.hasAttribute("required") || void 0,
|
|
3162
3233
|
value: getElementValue(element),
|
|
3234
|
+
hasValue: isNativeFormField(input) ? getElementHasValue(element) : getCustomTextFieldHasValue(input),
|
|
3163
3235
|
options: element instanceof HTMLSelectElement ? getSelectOptions(element) : void 0,
|
|
3164
3236
|
...buildBaseMetadata(input),
|
|
3165
3237
|
role,
|
|
@@ -3763,6 +3763,17 @@
|
|
|
3763
3763
|
background: var(--surface-active);
|
|
3764
3764
|
}
|
|
3765
3765
|
|
|
3766
|
+
.tool-chip-failed {
|
|
3767
|
+
border-left-color: color-mix(in srgb, var(--error) 60%, transparent);
|
|
3768
|
+
background: color-mix(in srgb, var(--error) 8%, var(--surface-hover));
|
|
3769
|
+
}
|
|
3770
|
+
|
|
3771
|
+
.tool-chip-failed .tool-chip-icon,
|
|
3772
|
+
.tool-chip-failed .tool-chip-args {
|
|
3773
|
+
color: color-mix(in srgb, var(--error) 80%, var(--text-muted));
|
|
3774
|
+
opacity: 1;
|
|
3775
|
+
}
|
|
3776
|
+
|
|
3766
3777
|
.tool-chip-icon {
|
|
3767
3778
|
flex-shrink: 0;
|
|
3768
3779
|
width: 16px;
|
|
@@ -6158,6 +6158,14 @@ function getSkillSlashSuggestions(value, kits, limit = 6) {
|
|
|
6158
6158
|
return left.kit.name.localeCompare(right.kit.name);
|
|
6159
6159
|
}).slice(0, limit).map(({ kit }) => kit);
|
|
6160
6160
|
}
|
|
6161
|
+
function canRunWithoutSlashTask(kit, inputKey) {
|
|
6162
|
+
if (inputKey !== "task") return false;
|
|
6163
|
+
const taskPlaceholder = `{{${inputKey}}}`;
|
|
6164
|
+
const placeholderIndex = kit.promptTemplate.indexOf(taskPlaceholder);
|
|
6165
|
+
if (placeholderIndex <= 0) return false;
|
|
6166
|
+
const leadingInstructions = kit.promptTemplate.slice(0, placeholderIndex).replace(/\{\{\w+\}\}/g, "").replace(/\btask\s*:?\s*$/i, "").trim();
|
|
6167
|
+
return /[a-z0-9]/i.test(leadingInstructions);
|
|
6168
|
+
}
|
|
6161
6169
|
function buildSlashSkillValues(kit, task) {
|
|
6162
6170
|
const values = {};
|
|
6163
6171
|
for (const input of kit.inputs) {
|
|
@@ -6167,12 +6175,15 @@ function buildSlashSkillValues(kit, task) {
|
|
|
6167
6175
|
if (targetInput) {
|
|
6168
6176
|
values[targetInput.key] = task;
|
|
6169
6177
|
}
|
|
6170
|
-
const missingLabels = kit.inputs.filter((input) => input.required).filter((input) =>
|
|
6178
|
+
const missingLabels = kit.inputs.filter((input) => input.required).filter((input) => {
|
|
6179
|
+
if (values[input.key]?.trim()) return false;
|
|
6180
|
+
return !canRunWithoutSlashTask(kit, input.key);
|
|
6181
|
+
}).map((input) => input.label);
|
|
6171
6182
|
return { values, missingLabels };
|
|
6172
6183
|
}
|
|
6173
6184
|
function renderKitPrompt(kit, values) {
|
|
6174
6185
|
for (const input of kit.inputs) {
|
|
6175
|
-
if (input.required && !values[input.key]?.trim()) {
|
|
6186
|
+
if (input.required && !values[input.key]?.trim() && !canRunWithoutSlashTask(kit, input.key)) {
|
|
6176
6187
|
logger$1.warn(
|
|
6177
6188
|
`Required field "${input.key}" is empty for kit "${kit.id}".`
|
|
6178
6189
|
);
|
|
@@ -7594,8 +7605,9 @@ const TOOL_ICONS = {
|
|
|
7594
7605
|
function renderToolChip(name, args) {
|
|
7595
7606
|
const icon = TOOL_ICONS[name] || "⚙";
|
|
7596
7607
|
const displayName = name.replace(/_/g, " ");
|
|
7608
|
+
const failed = args.trim().startsWith("⚠");
|
|
7597
7609
|
const argsHtml = args ? `<span class="tool-chip-args">${escapeHtml(args.length > MAX_PREVIEW_TEXT ? args.slice(0, TRUNCATE_KEEP) + "..." : args)}</span>` : "";
|
|
7598
|
-
return `<div class="tool-chip"><span class="tool-chip-icon">${icon}</span><span class="tool-chip-name">${escapeHtml(displayName)}</span>${argsHtml}</div>`;
|
|
7610
|
+
return `<div class="tool-chip${failed ? " tool-chip-failed" : ""}"><span class="tool-chip-icon">${icon}</span><span class="tool-chip-name">${escapeHtml(displayName)}</span>${argsHtml}</div>`;
|
|
7599
7611
|
}
|
|
7600
7612
|
function renderMarkdown(source) {
|
|
7601
7613
|
const codeBlocks = [];
|
|
@@ -10089,11 +10101,6 @@ ${contextBlock}` : contextBlock);
|
|
|
10089
10101
|
const kits = [...BUNDLED_KITS, ...installedKits];
|
|
10090
10102
|
const invocation = parseSkillSlashInvocation(prompt, kits);
|
|
10091
10103
|
if (invocation) {
|
|
10092
|
-
if (!invocation.task) {
|
|
10093
|
-
const [command] = prompt.split(/\s+/);
|
|
10094
|
-
setChatCommandError(`Add instructions after ${command}.`);
|
|
10095
|
-
return;
|
|
10096
|
-
}
|
|
10097
10104
|
const {
|
|
10098
10105
|
values,
|
|
10099
10106
|
missingLabels
|
package/out/renderer/index.html
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
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'; base-uri 'none'; object-src 'none'; frame-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; font-src 'self' data:; form-action 'self';" />
|
|
7
7
|
<title>Vessel</title>
|
|
8
|
-
<script type="module" crossorigin src="./assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
8
|
+
<script type="module" crossorigin src="./assets/index-l3uzsLbO.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="./assets/index-T8vlGvDJ.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quanta-intellect/vessel-browser",
|
|
3
3
|
"mcpName": "io.github.unmodeled-tyler/vessel-browser",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.141",
|
|
5
5
|
"description": "AI-native web browser runtime for autonomous agents with human supervision",
|
|
6
6
|
"main": "./out/main/index.js",
|
|
7
7
|
"bin": {
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
},
|
|
71
71
|
"repository": {
|
|
72
72
|
"type": "git",
|
|
73
|
-
"url": "https://github.com/unmodeled-tyler/
|
|
73
|
+
"url": "https://github.com/unmodeled-tyler/vessel-browser.git"
|
|
74
74
|
},
|
|
75
75
|
"engines": {
|
|
76
76
|
"node": ">=22.12.0",
|