surf-cli 2.4.0 → 2.4.1

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
@@ -378,18 +378,17 @@ Auto-cleanup: 24 hours TTL, 200MB max.
378
378
  Execute multi-step browser automation as a single command:
379
379
 
380
380
  ```bash
381
- # Inline workflow (newline-separated commands)
382
- surf do 'go "https://example.com/login"
383
- type "user@example.com" --selector "input[name=email]"
384
- type "password123" --selector "input[name=password]"
385
- click --selector "button[type=submit]"
386
- screenshot --output /tmp/after-login.png'
381
+ # Inline workflow (pipe-separated)
382
+ surf do 'go "https://example.com" | click e5 | screenshot'
387
383
 
388
- # From JSON file (same format as --script)
389
- surf do --file login-workflow.json
384
+ # Multi-step login flow
385
+ surf do 'go "https://example.com/login" | type "user@example.com" --selector "#email" | type "pass" --selector "#password" | click --selector "button[type=submit]"'
386
+
387
+ # From JSON file
388
+ surf do --file workflow.json
390
389
 
391
390
  # Validate without executing
392
- surf do 'go "url"\nclick e5\nscreenshot' --dry-run
391
+ surf do 'go "url" | click e5 | screenshot' --dry-run
393
392
  ```
394
393
 
395
394
  **Why workflows?** Instead of 6-8 separate CLI calls with LLM orchestration between each step, a workflow executes deterministically with smart auto-waits. Faster, cheaper, and more reliable.
package/native/cli.cjs CHANGED
@@ -817,9 +817,9 @@ const TOOLS = {
817
817
  "dry-run": "Parse and validate without executing"
818
818
  },
819
819
  examples: [
820
- { cmd: 'do \'go "https://example.com"\\nclick e5\\nscreenshot\'', desc: "Inline workflow" },
820
+ { cmd: 'do \'go "https://example.com" | click e5 | screenshot\'', desc: "Inline workflow" },
821
821
  { cmd: 'do -f login.json', desc: "From JSON file" },
822
- { cmd: 'do \'go "url"\\nclick e5\' --dry-run', desc: "Validate without running" },
822
+ { cmd: 'do \'go "url" | click e5\' --dry-run', desc: "Validate without running" },
823
823
  ]
824
824
  },
825
825
  }
@@ -206,17 +206,23 @@ function parseCommandLine(line) {
206
206
  }
207
207
 
208
208
  /**
209
- * Parse a multi-line workflow string into step array
210
- * @param {string} input - Multi-line workflow string
209
+ * Parse a workflow string into step array
210
+ * Supports pipe-separated (inline) or newline-separated (file) commands
211
+ * @param {string} input - Workflow string
211
212
  * @returns {Array<{ cmd: string, args: object }>}
212
213
  */
213
214
  function parseDoCommands(input) {
214
- // Replace literal \n (backslash + n) with actual newlines
215
- // This handles bash single-quoted strings like 'go "url"\nclick e5'
216
- const normalized = input.replace(/\\n/g, '\n');
215
+ // Determine separator: use pipe if present, otherwise newlines
216
+ // Pipe is preferred for inline: 'go "url" | click e5 | screenshot'
217
+ // Newlines for files or heredocs
218
+ const hasPipe = input.includes('|');
219
+ const separator = hasPipe ? '|' : '\n';
220
+
221
+ // Also handle literal \n for backwards compatibility
222
+ const normalized = hasPipe ? input : input.replace(/\\n/g, '\n');
217
223
 
218
224
  return normalized
219
- .split('\n')
225
+ .split(separator)
220
226
  .map(line => line.trim())
221
227
  .filter(line => line && !line.startsWith('#'))
222
228
  .map(line => parseCommandLine(line))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "surf-cli",
3
- "version": "2.4.0",
3
+ "version": "2.4.1",
4
4
  "description": "CLI for AI agents to control Chrome. Zero config, agent-agnostic, battle-tested.",
5
5
  "keywords": [
6
6
  "chrome",