Skip to content

Commit fcff2e4

Browse files
authored
feat(grok): add opt-in --web flow for grok ask (#193)
1 parent 4391ccf commit fcff2e4

File tree

4 files changed

+382
-79
lines changed

4 files changed

+382
-79
lines changed

SKILL.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,9 @@ opencli weread ranking --limit 10 # 排行榜
218218
opencli jimeng generate --prompt "描述" # AI 生图
219219
opencli jimeng history --limit 10 # 生成历史
220220

221-
# Grok (Desktop)
222-
opencli grok ask "问题" # 提问 Grok (text positional)
221+
# Grok (default + explicit web)
222+
opencli grok ask --prompt "问题" # 提问 Grok(兼容默认路径)
223+
opencli grok ask --prompt "问题" --web # 显式 grok.com consumer web UI 路径
223224

224225
# HuggingFace (public)
225226
opencli hf top --limit 10 # 热门模型

docs/adapters/browser/grok.md

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,28 @@
11
# Grok
22

3-
**Mode**: 🔐 Browser · **Domain**: `grok.com`
3+
**Mode**: Default Grok adapter + optional explicit consumer web path · **Domain**: `grok.com`
44

55
## Commands
66

77
| Command | Description |
88
|---------|-------------|
9-
| `opencli grok ask` | Send a message to Grok and get response |
9+
| `opencli grok ask` | Keep the default Grok ask behavior |
10+
| `opencli grok ask --web` | Use the explicit grok.com consumer web UI flow |
1011

1112
## Usage Examples
1213

1314
```bash
14-
# Ask Grok a question
15+
# Default / compatibility path
1516
opencli grok ask --prompt "Explain quantum computing in simple terms"
1617

17-
# Start a new chat session
18-
opencli grok ask --prompt "Hello" --new
18+
# Explicit consumer web path
19+
opencli grok ask --prompt "Explain quantum computing in simple terms" --web
20+
21+
# Best-effort fresh chat on the consumer web path
22+
opencli grok ask --prompt "Hello" --web --new
1923

2024
# Set custom timeout (default: 120s)
21-
opencli grok ask --prompt "Write a long essay" --timeout 180
25+
opencli grok ask --prompt "Write a long essay" --web --timeout 180
2226
```
2327

2428
### Options
@@ -27,9 +31,23 @@ opencli grok ask --prompt "Write a long essay" --timeout 180
2731
|--------|-------------|
2832
| `--prompt` | The message to send (required) |
2933
| `--timeout` | Wait timeout in seconds (default: 120) |
30-
| `--new` | Start a new chat session (default: false) |
34+
| `--new` | Start a new chat before sending (default: false) |
35+
| `--web` | Opt into the explicit grok.com consumer web flow (default: false) |
36+
37+
## Behavior
38+
39+
- `opencli grok ask` keeps the upstream/default behavior intact.
40+
- `opencli grok ask --web` switches to the newer hardened consumer-web implementation.
41+
- The `--web` path adds stricter composer detection, clearer blocked/session-gated hints, and waits for a stabilized assistant bubble before returning.
3142

3243
## Prerequisites
3344

34-
- Chrome running and **logged into** grok.com
45+
- The Grok adapter still depends on browser-backed access to `grok.com`
46+
- For `--web`, Chrome should already be running with an authenticated Grok consumer session
3547
- [Browser Bridge extension](/guide/browser-bridge) installed
48+
49+
## Caveats
50+
51+
- `--web` drives the Grok consumer web UI in the browser, not an API.
52+
- It depends on an already-authenticated session and can fail if Grok shows login, challenge, rate-limit, or other session-gating UI.
53+
- It may break when the Grok composer DOM, submit button behavior, or message bubble structure changes.

src/clis/grok/ask.test.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { describe, expect, it } from 'vitest';
2+
import { __test__ } from './ask.js';
3+
4+
describe('grok ask helpers', () => {
5+
it('normalizes boolean flags for explicit web routing', () => {
6+
expect(__test__.normalizeBooleanFlag(true)).toBe(true);
7+
expect(__test__.normalizeBooleanFlag('true')).toBe(true);
8+
expect(__test__.normalizeBooleanFlag('1')).toBe(true);
9+
expect(__test__.normalizeBooleanFlag('yes')).toBe(true);
10+
expect(__test__.normalizeBooleanFlag('on')).toBe(true);
11+
12+
expect(__test__.normalizeBooleanFlag(false)).toBe(false);
13+
expect(__test__.normalizeBooleanFlag('false')).toBe(false);
14+
expect(__test__.normalizeBooleanFlag(undefined)).toBe(false);
15+
});
16+
17+
it('ignores baseline bubbles and the echoed prompt when choosing the latest assistant candidate', () => {
18+
const candidate = __test__.pickLatestAssistantCandidate(
19+
['older assistant answer', 'Prompt text', 'Assistant draft', 'Assistant final'],
20+
1,
21+
'Prompt text',
22+
);
23+
24+
expect(candidate).toBe('Assistant final');
25+
});
26+
27+
it('returns empty when only the echoed prompt appeared after send', () => {
28+
const candidate = __test__.pickLatestAssistantCandidate(
29+
['older assistant answer', 'Prompt text'],
30+
1,
31+
'Prompt text',
32+
);
33+
34+
expect(candidate).toBe('');
35+
});
36+
37+
it('tracks stabilization by incrementing repeats and resetting on changes', () => {
38+
expect(__test__.updateStableState('', 0, 'First chunk')).toEqual({
39+
previousText: 'First chunk',
40+
stableCount: 0,
41+
});
42+
43+
expect(__test__.updateStableState('First chunk', 0, 'First chunk')).toEqual({
44+
previousText: 'First chunk',
45+
stableCount: 1,
46+
});
47+
48+
expect(__test__.updateStableState('First chunk', 1, 'Second chunk')).toEqual({
49+
previousText: 'Second chunk',
50+
stableCount: 0,
51+
});
52+
});
53+
});

0 commit comments

Comments
 (0)