Skip to content

Commit 60dc2f5

Browse files
committed
fix: keep auth handoff skills mode neutral
1 parent 0ba71d6 commit 60dc2f5

4 files changed

Lines changed: 34 additions & 11 deletions

File tree

skills/webcmd-autofix/SKILL.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@ When a `webcmd` command fails because a website changed its DOM, API, or respons
1212

1313
Hard stops before any code change:
1414

15-
- **`AUTH_REQUIRED`** (exit code 77): if a site login command exists, run `webcmd <site> login`, return its `action_required` instructions and `verify_command` (normally `webcmd <site> whoami`) to the user, and wait for them to report done in the visible browser. Run the returned `verify_command`; verification must succeed before retrying the original command. If no site login command exists, stop browser writes, hand the visible browser to the user, and wait. After they report done, take fresh browser state and use an available identity check or verify the intended post-action state before retrying. Their report alone is not verification. Never request, type, echo, store, or automate passwords, OTPs, recovery codes, cookies, or session secrets.
15+
- **Human-action handoff:** if a failure returns `handoff.status === action_required`, stop before trace collection or AutoFix. Give the user `handoff.action` and any `Webcmd browser:` or `handoff.viewUrl` link, then wait. Never request or enter credentials, passwords, or CAPTCHA answers. After the user reports done, run `handoff.verifyCommand` when present; verification must succeed before retrying. Without a verifier, inspect fresh browser state and verify the intended post-action state before any retry, especially for write commands.
16+
- **`AUTH_REQUIRED`** (exit code 77): if a site login command exists, run `webcmd <site> login`, give its `action_required` instructions and any returned `action_url` or `view_url` to the user, and wait. Run the returned `verify_command` (normally `webcmd <site> whoami`); verification must succeed before retrying the original command. If no site login command exists, stop browser writes, hand the visible browser to the user, and wait. After they report done, take fresh browser state and use an available identity check or verify the intended post-action state before retrying. Their report alone is not verification. Never request, type, echo, store, or automate passwords, OTPs, recovery codes, cookies, or session secrets.
1617
- **`BROWSER_CONNECT`** (exit code 69): stop. Tell the user to run `webcmd doctor`.
17-
- **CAPTCHA / raw-browser user takeover:** stop automation and let the user act in the visible browser. If handoff returned a `verify_command`, run it; verification must succeed before retrying. With no site login command and therefore no returned verifier, take fresh browser state and use an available identity check or verify the intended post-action state before retrying. The user's report alone is not verification. CAPTCHA is not an adapter issue.
18+
- **CAPTCHA / raw-browser user takeover:** stop automation. Follow the human-action handoff above when one is returned; otherwise let the user act in the visible browser. Verification must succeed before retrying. With no verifier, take fresh browser state and verify the intended post-action state before any retry. The user's report alone is not verification. CAPTCHA is not an adapter issue.
1819
- **Rate limiting / IP block:** stop. This is not an adapter issue.
1920

2021
Scope constraint:

skills/webcmd-browser/SKILL.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -337,15 +337,17 @@ webcmd browser hn open "https://news.ycombinator.com" \
337337

338338
### Authentication and human handoff
339339

340+
If a failure returns `handoff.status === action_required`, stop browser writes and AutoFix. Give the user `handoff.action` and any `Webcmd browser:` or `handoff.viewUrl` link, then wait. After the user reports done, run `handoff.verifyCommand` when present; verification must succeed before retrying.
341+
340342
1. On a clear login redirect or auth wall, stop browser writes.
341-
2. If the site exposes a login command, run `webcmd <site> login` and read its `action_required` result and returned `verify_command` (normally `webcmd <site> whoami`).
342-
3. Tell the user to complete sign-in in the visible browser. If there is no site login command, use the current browser.
343+
2. If the site exposes a login command, run `webcmd <site> login`. `already_logged_in` is verified; `in_progress` means no current user action, so do not ask the user or wait for confirmation, and do not poll; `action_required` is a hard stop.
344+
3. For `action_required`, give the user its instructions and any returned `action_url` or `view_url`. If Webcmd returned no URL, use the current visible browser.
343345
4. Never ask for or type passwords, OTPs, recovery codes, cookies, or session secrets.
344-
5. If login returned a `verify_command`, run that exact command after the user reports done; verification must succeed before retrying the original workflow.
345-
6. With no site login command and therefore no returned verifier, take fresh browser state and use an available identity check or verify the intended post-action state; that verification must succeed before retrying.
346-
7. Continue only from fresh browser state; refs from before handoff are stale.
346+
5. Run the returned `verify_command` (normally `webcmd <site> whoami`) or `handoff.verifyCommand` only after the user reports done; verification must succeed before retrying.
347+
6. Without a verifier, take fresh browser state and verify the intended post-action state before any retry, especially for write commands. The user's report alone is not verification.
348+
7. If login remains `in_progress`, perform a later explicit `whoami` or task retry when work next needs auth state. Use `webcmd auth refresh` only when an explicit auth-state refresh is needed.
347349

348-
For a CAPTCHA or user takeover, stop automation and let the user act in the visible browser. After the user reports done, apply the same conditional verification policy above; their report alone is not verification. Keep CAPTCHA outside automated retries.
350+
For a CAPTCHA or user takeover, stop automation, give the user any viewer URL Webcmd returned, and apply the same verification policy above. Keep CAPTCHA outside automated retries.
349351

350352
### Pick from a long dropdown
351353

skills/webcmd-usage/SKILL.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,11 @@ The error envelope includes a `trace` block pointing at `summary.md`. Patch only
120120

121121
## Authentication and Human Handoff
122122

123-
`AUTH_REQUIRED` is not an adapter failure. Run `webcmd <site> login`, return its `action_required` instructions and `verify_command` (normally `webcmd <site> whoami`) to the user, then wait for the user to report done in the visible browser. Run the returned `verify_command`; verification must succeed before retrying the original command. If the site has no login command, ask the user to sign in in the current Webcmd browser; after they report done, take fresh browser state and use an available identity check or verify the intended post-action state before retrying. Their report alone is not verification. Never request, type, echo, store, or automate passwords, OTPs, recovery codes, cookies, or session secrets; CAPTCHA stops automation and follows the same conditional verification rule.
123+
If a failure returns `handoff.status === action_required`, stop before AutoFix. Give the user `handoff.action` and any `Webcmd browser:` or `handoff.viewUrl` link, then wait. After the user reports done, run `handoff.verifyCommand` when present; verification must succeed before retrying.
124+
125+
`AUTH_REQUIRED` is not an adapter failure. Run `webcmd <site> login`: `already_logged_in` is verified; `in_progress` means no current user action, so do not ask the user or wait for confirmation, and do not poll; `action_required` is a hard stop. For `action_required`, give the user its instructions and any returned `action_url` or `view_url`, then wait. If Webcmd returned no URL, use the current visible browser.
126+
127+
Run the returned `verify_command` (normally `webcmd <site> whoami`) or `handoff.verifyCommand` only after the user reports done; verification must succeed before retrying. Without a verifier, take fresh browser state and verify the intended post-action state before any retry, especially for write commands. Use `webcmd auth refresh` only when an explicit auth-state refresh is needed. Their report alone is not verification. Never request, type, echo, store, or automate passwords, OTPs, recovery codes, cookies, session secrets, or CAPTCHA answers; CAPTCHA stops automation and follows the same verification rule.
124128

125129
## Report A Webcmd Defect
126130

src/skills.test.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,13 @@ describe('webcmd skills content', () => {
9393
]);
9494
});
9595

96-
it('enforces local authentication and human handoff policy', () => {
96+
it('enforces mode-neutral authentication and human handoff policy', () => {
9797
const browser = bundledSkill('webcmd-browser');
9898
const usage = bundledSkill('webcmd-usage');
9999
const autofix = bundledSkill('webcmd-autofix');
100100
const author = bundledSkill('webcmd-adapter-author');
101101
const skills = [browser, usage, autofix, author];
102+
const handoffSkills = [browser, usage, autofix];
102103
const autofixAuthRequired = autofix.match(/^- \*\*`AUTH_REQUIRED`\*\*[\s\S]*?(?=\n- \*\*)/m)?.[0] ?? '';
103104
const autofixAuthRequiredRow = autofix.split('\n')
104105
.find((line) => line.startsWith('| AUTH_REQUIRED |')) ?? '';
@@ -113,6 +114,21 @@ describe('webcmd skills content', () => {
113114
expect(usage).toContain('action_required');
114115
expect(autofix).toContain('webcmd <site> login');
115116
expect(author).toContain('registerSiteAuthCommands');
117+
for (const skill of handoffSkills) {
118+
expect(skill).toContain('handoff.status');
119+
expect(skill).toContain('handoff.viewUrl');
120+
expect(skill).toContain('handoff.verifyCommand');
121+
expect(skill).toContain('Webcmd browser:');
122+
expect(skill).not.toMatch(/\bhosted\b|\bKernel\b|\blocal mode\b|\blocally\b/i);
123+
}
124+
for (const skill of [browser, usage]) {
125+
expect(skill).toContain('already_logged_in');
126+
expect(skill).toContain('in_progress');
127+
expect(skill).toContain('action_url');
128+
expect(skill).toContain('view_url');
129+
expect(skill).toMatch(/in_progress[^\n]*(?:do not ask the user|do not wait for user confirmation)/i);
130+
expect(skill).toMatch(/(?:action_url|view_url|handoff\.viewUrl|Webcmd browser:)[\s\S]{0,300}user/i);
131+
}
116132
for (const skill of skills) {
117133
expect(skill).toContain('action_required');
118134
expect(skill).toContain('verify_command');
@@ -122,7 +138,7 @@ describe('webcmd skills content', () => {
122138
expect(skill).toMatch(/(?:must not|never).*?(?:password|secret|credential)/i);
123139
}
124140
for (const skill of [browser, usage, autofix]) {
125-
expect(skill).toMatch(/no (?:site )?login command[\s\S]{0,500}fresh browser state[\s\S]{0,500}(?:identity check|post-action state)[\s\S]{0,250}before retry/i);
141+
expect(skill).toMatch(/(?:no (?:site )?login command|without a verifier)[\s\S]{0,500}fresh browser state[\s\S]{0,500}(?:identity check|post-action state)[\s\S]{0,250}before (?:any )?retry/i);
126142
}
127143
expect(autofixAuthRequired).toMatch(/if (?:a|the) site login command exists[\s\S]*webcmd <site> login[\s\S]*returned `verify_command`[\s\S]*verification must succeed[\s\S]*retry/i);
128144
expect(autofixAuthRequired).toMatch(/no site login command[\s\S]*stop (?:browser )?writes[\s\S]*visible browser[\s\S]*fresh browser state[\s\S]*(?:identity check|post-action state)[\s\S]*before retry[\s\S]*report alone is not verification/i);

0 commit comments

Comments
 (0)