surf-cli 2.15.1 → 2.15.2

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 CHANGED
@@ -526,7 +526,7 @@ surf aistudio.build "game" --keep-open --timeout 600 # Keep tab open, 1
526
526
 
527
527
  #### Oracle
528
528
 
529
- Use `surf oracle` for a durable, local ChatGPT consult instead of a quick `surf chatgpt` one-shot. It persists jobs by conversation URL, supports repeatable file-context globs, and verifies requested model and reasoning effort before submission. ChatGPT model aliases include `instant`, `thinking`, `pro`, `gpt-5.5`, and `gpt-5.6-sol`; `pro` selects the current ChatGPT GPT-5.6 Sol Pro web mode.
529
+ Use `surf oracle` for a durable, local ChatGPT consult instead of a quick `surf chatgpt` one-shot. It persists jobs by conversation URL, supports repeatable file-context globs, and verifies requested model and reasoning effort before submission. ChatGPT model aliases include `instant`, `thinking`, `pro`, `gpt-5.5`, and `gpt-5.6-sol`. Use `--model gpt-5.6-sol --effort pro` for GPT-5.6 Sol with Pro effort.
530
530
 
531
531
  ```bash
532
532
  surf oracle ask "review this change" --files "src/**/*.ts" --model gpt-5.5 --effort pro --detach --json
@@ -996,9 +996,9 @@ pi -e /path/to/surf-cli/pi-extension/surf.ts
996
996
 
997
997
  It registers `surf_read`, `surf_screenshot`, `surf_click`, `surf_type`, `surf_tool`, and the `surf_oracle_*` tools. Browser calls use Surf's native-host socket, not shell commands. If `pi-subagents/background-work` is installed, the extension also reports active oracle jobs started by that Pi session. Pi still loads the browser tools when pi-subagents is not installed.
998
998
 
999
- The extension also registers a `surf-oracle` external-job provider when a Pi runtime exposes that provider bridge. The provider implements pi-subagents' external-job contract: `start`, `status`, `result`, and `reattach` operations that return `providerJobId`, a contract state (`queued`, `running`, `completed`, `failed`), the durable conversation URL, the captured result text as `output`, and failure code and message when present. It reads `options.model` and `options.effort` for starts, so a Pi profile can request `model: pro` and reach the ChatGPT GPT-5.6 Sol Pro web mode through Surf. Capacity stays fail-closed: Surf returns the blocking job id instead of silently queueing a second ChatGPT job.
999
+ The extension also registers a `surf-oracle` external-job provider when a Pi runtime exposes that provider bridge. The provider implements pi-subagents' external-job contract: `start`, `status`, `result`, and `reattach` operations that return `providerJobId`, a contract state (`queued`, `running`, `completed`, `failed`), the durable conversation URL, the captured result text as `output`, and failure code and message when present. It reads `options.model` and `options.effort` for starts, so a Pi profile can request `model: gpt-5.6-sol` plus `effort: pro` and reach ChatGPT GPT-5.6 Sol with Pro effort through Surf. Capacity stays fail-closed: Surf returns the blocking job id instead of silently queueing a second ChatGPT job.
1000
1000
 
1001
- When Surf is installed as a Pi package, it also exposes an optional `gpt-pro` package agent for `pi-subagents`. That profile uses `runner.type: external-job`, provider `surf-oracle`, and `options.model: pro`. Surf remains useful without Pi or `pi-subagents`; the package agent only wires Surf's browser-backed model alias into Pi's agent picker.
1001
+ When Surf is installed as a Pi package, it also exposes an optional `gpt-pro` package agent for `pi-subagents`. That profile uses `runner.type: external-job`, provider `surf-oracle`, `options.model: gpt-5.6-sol`, and `options.effort: pro`. Surf remains useful without Pi or `pi-subagents`; the package agent only wires Surf's browser-backed model alias into Pi's agent picker.
1002
1002
 
1003
1003
  Shell-based agents should select a unique session with `SURF_SESSION` and call `surf session.ensure` before their first browser command. The optional Pi extension still uses its existing socket-tool interface; callers that coordinate several Pi workers should pass explicit tab targets until session selection is exposed by that integration.
1004
1004
 
package/agents/gpt-pro.md CHANGED
@@ -5,7 +5,8 @@ runner:
5
5
  type: external-job
6
6
  provider: surf-oracle
7
7
  options:
8
- model: pro
8
+ model: gpt-5.6-sol
9
+ effort: pro
9
10
  async: true
10
11
  systemPromptMode: replace
11
12
  inheritProjectContext: false
@@ -4,7 +4,7 @@ const CHATGPT_MODEL_ALIASES = new Map([
4
4
  ["gpt53", "instant"],
5
5
  ["thinking", "thinking"],
6
6
  ["gpt54thinking", "thinking"],
7
- ["pro", "gpt56sol"],
7
+ ["pro", "pro"],
8
8
  ["gpt54pro", "pro"],
9
9
  ["55", "gpt55"],
10
10
  ["gpt55", "gpt55"],
@@ -191,11 +191,22 @@ async function readPicker(cdp, kind, click = false) {
191
191
  `(() => {
192
192
  ${buildClickDispatcher()}
193
193
  const kind = ${JSON.stringify(kind)};
194
- const nodes = Array.from(document.querySelectorAll(${JSON.stringify(selector)})).filter((node) => {
194
+ let nodes = Array.from(document.querySelectorAll(${JSON.stringify(selector)})).filter((node) => {
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');
197
- return value.includes('thinking') || value.includes('pro');
196
+ if (kind !== 'model') return value.includes('thinking') || value.includes('pro');
197
+ return value.includes('gpt') || value.includes('thinking') || value.includes('instant');
198
198
  });
199
+ if (kind === 'model' && nodes.length === 0) {
200
+ nodes = Array.from(document.querySelectorAll(${JSON.stringify(selector)})).filter((node) => {
201
+ const value = ((node.getAttribute?.('aria-label') || '') + ' ' + (node.textContent || '')).toLowerCase();
202
+ return value.includes('pro');
203
+ });
204
+ }
205
+ if (kind === 'model' && nodes.length === 0) {
206
+ nodes = Array.from(document.querySelectorAll(${JSON.stringify(selector)})).filter((node) =>
207
+ node.getAttribute?.('aria-haspopup') === 'menu' || node.getAttribute?.('aria-expanded') !== null
208
+ );
209
+ }
199
210
  const items = nodes.map((node) => {
200
211
  const text = (node.textContent || '').replace(/\\s+/g, ' ').trim();
201
212
  const aria = (node.getAttribute?.('aria-label') || '').replace(/\\s+/g, ' ').trim();
@@ -329,6 +340,12 @@ async function selectModel(cdp, desiredModel, timeoutMs = 8000, signal) {
329
340
  if (picker?.items?.length !== 1) throw verificationError("model", desiredModel);
330
341
  await delay(300, signal);
331
342
  const menu = await waitForMenu(cdp, "model", timeoutMs, signal);
343
+ const currentAdvancedModel = verifyChatGPTModelSelection(
344
+ menu.items.filter((item) => /\bmodel\b/i.test(String(item?.label || ""))),
345
+ desiredModel,
346
+ );
347
+ if (currentAdvancedModel) return currentAdvancedModel.displayLabel || currentAdvancedModel.label;
348
+
332
349
  const match = resolveChatGPTModelMenuOption(menu.items, desiredModel);
333
350
  if (!match || !(await clickMenuItem(cdp, "model", match))) {
334
351
  throw verificationError("model", desiredModel, menu.items);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "surf-cli",
3
- "version": "2.15.1",
3
+ "version": "2.15.2",
4
4
  "description": "CLI for AI agents to control Chrome. Zero config, agent-agnostic, battle-tested.",
5
5
  "keywords": [
6
6
  "chrome",
@@ -112,11 +112,11 @@ surf oracle result <job-id> --wait --json
112
112
 
113
113
  `status` reads persisted state without touching Chrome. `result` attempts to harvest the answer and returns the job object with `response` once its state is `captured`. A Ctrl-C during waiting exits with status 130 and prints `Recover with: surf oracle result <id>`. Once the job is `awaiting`, the persisted ChatGPT conversation URL is its durable key, so `surf oracle result <id>` can recover after CLI exit, native-host restart, or Chrome restart by reopening that conversation.
114
114
 
115
- Treat Pro quota as scarce. Oracle never selects Pro implicitly; request it with `--model pro` or `--effort pro`. ChatGPT model aliases include `instant`, `thinking`, `pro`, `gpt-5.5`, and `gpt-5.6-sol`. Accepted `--effort` values are `light`, `standard`, `extended`, `heavy`, and `pro`. Requested model and effort selections are read back before submission, and an unverifiable selection fails with `model_verification_failed` instead of silently continuing. Capacity is one non-terminal oracle job. A `capacity` error includes the in-flight job ID; poll that job or wait for it to finish rather than submitting the same consult again.
115
+ Treat Pro quota as scarce. Oracle never selects Pro effort implicitly; request it with `--effort pro`. ChatGPT model aliases include `instant`, `thinking`, `pro`, `gpt-5.5`, and `gpt-5.6-sol`. Accepted `--effort` values are `light`, `standard`, `extended`, `heavy`, and `pro`. Use `--model gpt-5.6-sol --effort pro` for GPT-5.6 Sol with Pro effort. Requested model and effort selections are read back before submission, and an unverifiable selection fails with `model_verification_failed` instead of silently continuing. Capacity is one non-terminal oracle job. A `capacity` error includes the in-flight job ID; poll that job or wait for it to finish rather than submitting the same consult again.
116
116
 
117
- When loaded as a Pi extension, Surf also registers a `surf-oracle` external-job provider when the runtime exposes that bridge. The provider maps `start`, `status`, `result`, and `reattach` to durable Surf Oracle jobs and returns pi-subagents' external-job contract shape: `providerJobId`, a contract state (`queued`, `running`, `completed`, `failed`), the conversation URL, the captured result text as `output`, and failure code and message. It honors `options.model` and `options.effort` for starts, so `model: pro` selects ChatGPT GPT-5.6 Sol Pro web mode through the browser. `reattach` only harvests an existing job by ID; it never submits the prompt again.
117
+ When loaded as a Pi extension, Surf also registers a `surf-oracle` external-job provider when the runtime exposes that bridge. The provider maps `start`, `status`, `result`, and `reattach` to durable Surf Oracle jobs and returns pi-subagents' external-job contract shape: `providerJobId`, a contract state (`queued`, `running`, `completed`, `failed`), the conversation URL, the captured result text as `output`, and failure code and message. It honors `options.model` and `options.effort` for starts, so `model: gpt-5.6-sol` plus `effort: pro` selects ChatGPT GPT-5.6 Sol with Pro effort through the browser. `reattach` only harvests an existing job by ID; it never submits the prompt again.
118
118
 
119
- When Surf is installed as a Pi package, it exposes an optional `gpt-pro` package agent for `pi-subagents`. That profile uses `runner.type: external-job`, provider `surf-oracle`, and `options.model: pro`. Surf remains useful without Pi or `pi-subagents`.
119
+ When Surf is installed as a Pi package, it exposes an optional `gpt-pro` package agent for `pi-subagents`. That profile uses `runner.type: external-job`, provider `surf-oracle`, `options.model: gpt-5.6-sol`, and `options.effort: pro`. Surf remains useful without Pi or `pi-subagents`.
120
120
 
121
121
  Context comes from repeatable `--files` globs. Surf fails closed when a glob matches nothing or a matched file is unreadable, binary, or invalid UTF-8. It also blocks gitignored files and basenames matching `.env*`, `*.pem`, `*.key`, `id_rsa*`, `id_ed25519*`, `*.p12`, `*.pfx`, `credentials*`, or `secrets*`. Use `--allow-sensitive` only after intentionally reviewing those files; it overrides the block rather than redacting content. Context up to 60,000 evidence characters is inserted inline, while larger context becomes one private text attachment. The assembly manifest records each path, byte count, SHA-256, inline or bundle disposition, and deny-list outcome.
122
122