surf-cli 2.13.1 → 2.15.0
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 +65 -34
- package/agents/gpt-pro.md +19 -0
- package/dist/content/index.js +116 -0
- package/dist/content/index.js.map +1 -0
- package/dist/icons/icon-128.png +0 -0
- package/dist/icons/icon-16.png +0 -0
- package/dist/icons/icon-48.png +0 -0
- package/dist/manifest.json +2 -11
- package/dist/options/options.js +3 -3
- package/dist/options/options.js.map +1 -1
- package/dist/service-worker/index.js +261 -61
- package/dist/service-worker/index.js.map +1 -1
- package/native/browser-scheduler.cjs +348 -0
- package/native/browser-session-store.cjs +271 -0
- package/native/chatgpt-client-selection.cjs +20 -10
- package/native/chatgpt-client-ui.cjs +35 -7
- package/native/cli.cjs +333 -62
- package/native/do-executor.cjs +5 -0
- package/native/host-helpers.cjs +19 -3
- package/native/host-sessions.cjs +8 -1
- package/native/host.cjs +766 -19
- package/native/mcp-server.cjs +1 -1
- package/native/oracle-cli.cjs +2 -2
- package/native/oracle-jobs.cjs +25 -3
- package/native/playbook-cli.cjs +16 -3
- package/native/surf-error.cjs +47 -0
- package/native/tool-scope.cjs +107 -0
- package/native/workflow-definition.cjs +7 -0
- package/package.json +8 -2
- package/pi-extension/surf.ts +275 -2
- package/skills/surf/SKILL.md +52 -23
- package/dist/content/accessibility-tree.js +0 -11
- package/dist/content/accessibility-tree.js.map +0 -1
- package/dist/content/visual-indicator.js +0 -111
- package/dist/content/visual-indicator.js.map +0 -1
|
@@ -18,9 +18,10 @@ const SELECTORS = {
|
|
|
18
18
|
loginCta: 'a[href*="/auth/login"], button',
|
|
19
19
|
sendButton:
|
|
20
20
|
'button[data-testid="send-button"], button[data-testid*="composer-send"], form button[type="submit"]',
|
|
21
|
-
modelButton:
|
|
21
|
+
modelButton:
|
|
22
|
+
'[data-testid="model-switcher-dropdown-button"], [data-testid="composer-footer-actions"] button[aria-haspopup="menu"], button.__composer-pill[aria-haspopup="menu"], .__composer-pill-composite button[aria-haspopup="menu"]',
|
|
22
23
|
modelMenu: '[role="menu"][data-radix-menu-content]',
|
|
23
|
-
modelMenuItem: '[role="
|
|
24
|
+
modelMenuItem: 'button, [role="menuitem"], [role="menuitemradio"]',
|
|
24
25
|
menuItemPrimaryLabel: '.min-w-0 > span',
|
|
25
26
|
effortButton:
|
|
26
27
|
'[data-testid="composer-footer-actions"] button[aria-haspopup="menu"], button.__composer-pill[aria-haspopup="menu"], .__composer-pill-composite button[aria-haspopup="menu"]',
|
|
@@ -191,8 +192,8 @@ async function readPicker(cdp, kind, click = false) {
|
|
|
191
192
|
${buildClickDispatcher()}
|
|
192
193
|
const kind = ${JSON.stringify(kind)};
|
|
193
194
|
const nodes = Array.from(document.querySelectorAll(${JSON.stringify(selector)})).filter((node) => {
|
|
194
|
-
if (kind === 'model') return true;
|
|
195
195
|
const value = ((node.getAttribute?.('aria-label') || '') + ' ' + (node.textContent || '')).toLowerCase();
|
|
196
|
+
if (kind === 'model') return value.includes('gpt') || value.includes('pro') || value.includes('thinking') || value.includes('instant');
|
|
196
197
|
return value.includes('thinking') || value.includes('pro');
|
|
197
198
|
});
|
|
198
199
|
const items = nodes.map((node) => {
|
|
@@ -224,13 +225,31 @@ async function readMenu(cdp, kind, allowSubmenu) {
|
|
|
224
225
|
const choices = ${JSON.stringify(CHATGPT_EFFORT_CHOICES)};
|
|
225
226
|
const containers = Array.from(document.querySelectorAll(${JSON.stringify(menuSelector)}));
|
|
226
227
|
const normalize = (value) => String(value || '').toLowerCase().replace(/[^a-z0-9]+/g, ' ').trim();
|
|
227
|
-
let menu = isModel ? containers
|
|
228
|
+
let menu = isModel ? containers.find((container) => {
|
|
229
|
+
const labels = Array.from(container.querySelectorAll(${JSON.stringify(itemSelector)}))
|
|
230
|
+
.filter((item) => item.getAttribute?.('aria-haspopup') !== 'menu')
|
|
231
|
+
.map((item) => normalize((item.getAttribute?.('aria-label') || '') + ' ' + (item.textContent || '')));
|
|
232
|
+
return labels.some((label) => label.includes('gpt') || /^o[0-9]/.test(label));
|
|
233
|
+
}) : containers.find((container) => {
|
|
228
234
|
const label = normalize(container.querySelector?.(${JSON.stringify(SELECTORS.effortMenuLabel)})?.textContent);
|
|
229
235
|
const levels = new Set(Array.from(container.querySelectorAll(${JSON.stringify(itemSelector)}))
|
|
230
236
|
.flatMap((item) => normalize(item.textContent).split(/\\s+/))
|
|
231
237
|
.filter((word) => choices.includes(word)));
|
|
232
238
|
return label.includes('thinking time') || levels.size >= 2;
|
|
233
239
|
});
|
|
240
|
+
if (!menu && isModel && ${allowSubmenu}) {
|
|
241
|
+
for (const container of containers) {
|
|
242
|
+
const trigger = Array.from(container.querySelectorAll(${JSON.stringify(SELECTORS.effortSubmenuTrigger)}))
|
|
243
|
+
.find((item) => {
|
|
244
|
+
const label = normalize((item.getAttribute?.('aria-label') || '') + ' ' + (item.textContent || ''));
|
|
245
|
+
return label.includes('model') || label.includes('advanced');
|
|
246
|
+
});
|
|
247
|
+
if (trigger) {
|
|
248
|
+
dispatchClickSequence(trigger);
|
|
249
|
+
return { found: false, submenuOpened: true, items: [] };
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
234
253
|
if (!menu && !isModel && ${allowSubmenu}) {
|
|
235
254
|
for (const container of containers) {
|
|
236
255
|
const trigger = Array.from(container.querySelectorAll(${JSON.stringify(SELECTORS.effortSubmenuTrigger)}))
|
|
@@ -299,7 +318,7 @@ async function clickMenuItem(cdp, kind, match) {
|
|
|
299
318
|
.replace(/\\s+/g, ' ').trim().slice(0, 80);
|
|
300
319
|
return label === expectedLabel;
|
|
301
320
|
});
|
|
302
|
-
return matches.length
|
|
321
|
+
return matches.length >= 1 ? dispatchClickSequence(matches[0]) : false;
|
|
303
322
|
})()`,
|
|
304
323
|
);
|
|
305
324
|
}
|
|
@@ -317,8 +336,17 @@ async function selectModel(cdp, desiredModel, timeoutMs = 8000, signal) {
|
|
|
317
336
|
await delay(200, signal);
|
|
318
337
|
const state = await readPicker(cdp, "model");
|
|
319
338
|
const verified = verifyChatGPTModelSelection(state?.items, desiredModel);
|
|
320
|
-
if (
|
|
321
|
-
|
|
339
|
+
if (verified) return verified.displayLabel || verified.label;
|
|
340
|
+
|
|
341
|
+
const reopened = await readPicker(cdp, "model", true);
|
|
342
|
+
if (reopened?.items?.length !== 1) throw verificationError("model", desiredModel, menu.items);
|
|
343
|
+
const readbackMenu = await waitForMenu(cdp, "model", timeoutMs, signal);
|
|
344
|
+
const readbackVerified = verifyChatGPTModelSelection(
|
|
345
|
+
readbackMenu.items.filter((item) => item.selected),
|
|
346
|
+
desiredModel,
|
|
347
|
+
);
|
|
348
|
+
if (!readbackVerified) throw verificationError("model", desiredModel, readbackMenu.items);
|
|
349
|
+
return readbackVerified.label;
|
|
322
350
|
}
|
|
323
351
|
|
|
324
352
|
async function selectEffort(cdp, desiredEffort, timeoutMs = 8000, signal) {
|