surf-skill 2.1.0 → 2.1.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/CHANGELOG.md +41 -0
- package/SKILL.md +1 -1
- package/bin/surf-skill.mjs +1 -1
- package/package.json +1 -1
- package/src/lib/dispatch.mjs +1 -1
- package/src/lib/providers/brave.mjs +7 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,46 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v2.1.1 — Robust key rotation: Brave 422 now burns the key
|
|
4
|
+
|
|
5
|
+
### Bug
|
|
6
|
+
|
|
7
|
+
When a Brave key was malformed (wrong length/charset), the API returns
|
|
8
|
+
HTTP **422** rather than 401. v2.1.0 classified 422 as `caller_4xx`, which
|
|
9
|
+
made dispatch throw without burning the key or trying the next one. That
|
|
10
|
+
violated the cross-provider fallback contract: a single bad-format key
|
|
11
|
+
could short-circuit the chain instead of rotating.
|
|
12
|
+
|
|
13
|
+
### Fix
|
|
14
|
+
|
|
15
|
+
`src/lib/providers/brave.mjs::mapError` now classifies 422 as `auth`
|
|
16
|
+
(burn key, rotate). The trade-off:
|
|
17
|
+
|
|
18
|
+
- **Real malformed token** → burns the key, dispatch tries the next key
|
|
19
|
+
(or next provider if `--provider` not set). The user gets a result.
|
|
20
|
+
- **Genuinely bad query param** → all keys fail with 422; surfaces as
|
|
21
|
+
`AllProvidersExhausted` with a hint, still actionable.
|
|
22
|
+
|
|
23
|
+
### Verified
|
|
24
|
+
|
|
25
|
+
Re-ran the 3 fallback tests with v2.1.1:
|
|
26
|
+
|
|
27
|
+
- T1 same-provider rotation (tavily key #0 bad → key #1 succeeds): ✓
|
|
28
|
+
- T2 cross-provider fallback (tavily/parallel both 401 → brave 200): ✓
|
|
29
|
+
- T3 all keys bad incl. malformed Brave: **now burns Brave key + reports
|
|
30
|
+
AllProvidersExhausted** (instead of throwing on the 422)
|
|
31
|
+
|
|
32
|
+
### Also fixed
|
|
33
|
+
|
|
34
|
+
- `src/lib/dispatch.mjs::VERSION` was stuck at `1.0.0` since the initial
|
|
35
|
+
release; bumped to `2.1.1` so the `X-Client-Name` header surfaces
|
|
36
|
+
the correct CLI version to providers.
|
|
37
|
+
- `SKILL.md::metadata.version` was missed in the v2.1.0 bump (still
|
|
38
|
+
showed `2.0.0`); now `2.1.1`.
|
|
39
|
+
|
|
40
|
+
No breaking changes.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
3
44
|
## v2.1.0 — Brave Search as 3rd provider + `--mode` flag
|
|
4
45
|
|
|
5
46
|
### What's new
|
package/SKILL.md
CHANGED
|
@@ -4,7 +4,7 @@ description: Web search, content extraction, site crawl, URL mapping, and deep r
|
|
|
4
4
|
license: MIT
|
|
5
5
|
allowed-tools: bash
|
|
6
6
|
metadata:
|
|
7
|
-
version: "2.
|
|
7
|
+
version: "2.1.1"
|
|
8
8
|
requires: "node>=18; install via `npm i -g surf-skill`; keys via 'surf-skill setup' (multi-key wizard); per-project bash timeout via 'surf-skill project-config'"
|
|
9
9
|
---
|
|
10
10
|
|
package/bin/surf-skill.mjs
CHANGED
|
@@ -15,7 +15,7 @@ import { runProjectConfig, formatProjectConfigResult } from '../src/lib/project-
|
|
|
15
15
|
import { providerFromRequestId } from '../src/lib/providers/index.mjs';
|
|
16
16
|
import { progress, setSilent } from '../src/lib/progress.mjs';
|
|
17
17
|
|
|
18
|
-
const VERSION = '2.1.
|
|
18
|
+
const VERSION = '2.1.1';
|
|
19
19
|
|
|
20
20
|
// Catch SIGTERM/SIGINT so a harness-driven kill surfaces a useful message
|
|
21
21
|
// instead of dying silently. This is defense-in-depth: dispatch already
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "surf-skill",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "Multi-provider web skill (Tavily + Parallel AI + Brave Search) for AI coding agents — CLI + Node library + Anthropic Agent Skill. Auto-fallback, multi-key rotation, --mode tiers, per-project timeout config.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.mjs",
|
package/src/lib/dispatch.mjs
CHANGED
|
@@ -13,7 +13,7 @@ import { sleep } from './flags.mjs';
|
|
|
13
13
|
import { progress } from './progress.mjs';
|
|
14
14
|
|
|
15
15
|
const CACHEABLE = new Set(['search', 'extract', 'map']);
|
|
16
|
-
const VERSION = '1.
|
|
16
|
+
const VERSION = '2.1.1';
|
|
17
17
|
|
|
18
18
|
// Detect the agent harness's bash timeout from env vars. The number is the
|
|
19
19
|
// total time (ms) the harness will allow our process to live before SIGTERM.
|
|
@@ -90,7 +90,13 @@ function mapError(status, body) {
|
|
|
90
90
|
if (status === 401) return { kind: 'auth', statusCode: status, message: 'invalid Brave key' };
|
|
91
91
|
if (status === 402) return { kind: 'auth', statusCode: status, message: msg || 'Brave: insufficient credits / billing required' };
|
|
92
92
|
if (status === 403) return { kind: 'auth', statusCode: status, message: msg || 'forbidden (plan/billing)' };
|
|
93
|
-
|
|
93
|
+
// Brave returns 422 for several reasons: malformed token (length/charset
|
|
94
|
+
// wrong, fails BEFORE auth check), OR bad query params. We classify 422 as
|
|
95
|
+
// `auth` so the key gets burned and dispatch rotates. The trade-off: a
|
|
96
|
+
// genuinely-bad query param will fail across ALL keys and surface as
|
|
97
|
+
// AllProvidersExhausted, still actionable. A malformed token is the
|
|
98
|
+
// dominant cause in practice (real tokens hit 401 instead).
|
|
99
|
+
if (status === 422) return { kind: 'auth', statusCode: status, message: msg || 'Brave: malformed token or invalid params (key rotation will retry; if all keys fail, you likely have a bad query)' };
|
|
94
100
|
if (status === 429) return { kind: 'rate_limit_429', statusCode: status, message: msg || 'Brave rate limit (50 RPS search)' };
|
|
95
101
|
if (status >= 500) return { kind: 'server_5xx', statusCode: status, message: msg || 'Brave server error' };
|
|
96
102
|
if (status >= 400) return { kind: 'caller_4xx', statusCode: status, message: msg || `HTTP ${status}` };
|