abelworkflow 0.6.1 → 0.6.3
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 +30 -0
- package/package.json +1 -1
- package/skills/dev-browser/scripts/start.ts +1 -0
- package/skills/dev-browser/src/runtime.test.ts +60 -0
- package/skills/dev-browser/src/runtime.ts +27 -3
- package/skills/grok-search/SKILL.md +51 -5
- package/skills/dev-browser/resolve-skill-dir.sh +0 -35
package/README.md
CHANGED
|
@@ -142,18 +142,36 @@ git -C "$HOME\.agents" pull
|
|
|
142
142
|
|
|
143
143
|
#### 2. 执行本地初始化
|
|
144
144
|
|
|
145
|
+
**Linux/macOS(bash/zsh)**
|
|
146
|
+
|
|
145
147
|
```bash
|
|
146
148
|
cd ~/.agents
|
|
147
149
|
node bin/abelworkflow.mjs
|
|
148
150
|
```
|
|
149
151
|
|
|
152
|
+
**Windows(PowerShell)**
|
|
153
|
+
|
|
154
|
+
```powershell
|
|
155
|
+
Set-Location "$HOME\.agents"
|
|
156
|
+
node .\bin\abelworkflow.mjs
|
|
157
|
+
```
|
|
158
|
+
|
|
150
159
|
如果只想重建链接,不进入菜单:
|
|
151
160
|
|
|
161
|
+
**Linux/macOS(bash/zsh)**
|
|
162
|
+
|
|
152
163
|
```bash
|
|
153
164
|
cd ~/.agents
|
|
154
165
|
node bin/abelworkflow.mjs install
|
|
155
166
|
```
|
|
156
167
|
|
|
168
|
+
**Windows(PowerShell)**
|
|
169
|
+
|
|
170
|
+
```powershell
|
|
171
|
+
Set-Location "$HOME\.agents"
|
|
172
|
+
node .\bin\abelworkflow.mjs install
|
|
173
|
+
```
|
|
174
|
+
|
|
157
175
|
### 映射关系(本仓库 → 配置目录)
|
|
158
176
|
|
|
159
177
|
| 本仓库 | Claude Code | Codex | 说明 |
|
|
@@ -164,9 +182,21 @@ node bin/abelworkflow.mjs install
|
|
|
164
182
|
|
|
165
183
|
### 验证(可选)
|
|
166
184
|
|
|
185
|
+
**Linux/macOS(bash/zsh)**
|
|
186
|
+
|
|
167
187
|
```bash
|
|
168
188
|
ls -la "$HOME/.claude/CLAUDE.md" "$HOME/.claude/commands/oc"
|
|
169
189
|
ls -la "$HOME/.codex/AGENTS.md" "$HOME/.codex/prompts/"{init,research,plan,implementation,diagnose}.md
|
|
170
190
|
cat "$HOME/.claude/settings.json" | head
|
|
171
191
|
cat "$HOME/.codex/config.toml" | head
|
|
172
192
|
```
|
|
193
|
+
|
|
194
|
+
**Windows(PowerShell)**
|
|
195
|
+
|
|
196
|
+
```powershell
|
|
197
|
+
Get-Item "$HOME\.claude\CLAUDE.md", "$HOME\.claude\commands\oc"
|
|
198
|
+
Get-Item "$HOME\.codex\AGENTS.md"
|
|
199
|
+
Get-ChildItem "$HOME\.codex\prompts" | Where-Object { $_.Name -in @("init.md", "research.md", "plan.md", "implementation.md", "diagnose.md") }
|
|
200
|
+
Get-Content "$HOME\.claude\settings.json" -TotalCount 10
|
|
201
|
+
Get-Content "$HOME\.codex\config.toml" -TotalCount 10
|
|
202
|
+
```
|
package/package.json
CHANGED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
|
|
3
|
+
import { describe, expect, it } from "vitest";
|
|
4
|
+
|
|
5
|
+
import { getPlaywrightBrowserRoots, isPlaywrightChromiumInstalled } from "./runtime.js";
|
|
6
|
+
|
|
7
|
+
describe("getPlaywrightBrowserRoots", () => {
|
|
8
|
+
const skillDir = "/tmp/dev-browser";
|
|
9
|
+
|
|
10
|
+
it("uses the hermetic local browser directory when PLAYWRIGHT_BROWSERS_PATH is 0", () => {
|
|
11
|
+
expect(
|
|
12
|
+
getPlaywrightBrowserRoots({
|
|
13
|
+
skillDir,
|
|
14
|
+
platform: "win32",
|
|
15
|
+
env: { PLAYWRIGHT_BROWSERS_PATH: "0" },
|
|
16
|
+
})
|
|
17
|
+
).toEqual([join(skillDir, "node_modules", "playwright-core", ".local-browsers")]);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("prefers LOCALAPPDATA on Windows before USERPROFILE fallback", () => {
|
|
21
|
+
expect(
|
|
22
|
+
getPlaywrightBrowserRoots({
|
|
23
|
+
skillDir,
|
|
24
|
+
platform: "win32",
|
|
25
|
+
env: {
|
|
26
|
+
LOCALAPPDATA: "C:\\Users\\Alice\\AppData\\Local",
|
|
27
|
+
USERPROFILE: "C:\\Users\\Alice",
|
|
28
|
+
},
|
|
29
|
+
})
|
|
30
|
+
).toEqual([join("C:\\Users\\Alice\\AppData\\Local", "ms-playwright")]);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("falls back to USERPROFILE when LOCALAPPDATA is unavailable", () => {
|
|
34
|
+
expect(
|
|
35
|
+
getPlaywrightBrowserRoots({
|
|
36
|
+
skillDir,
|
|
37
|
+
platform: "win32",
|
|
38
|
+
env: { USERPROFILE: "C:\\Users\\Alice" },
|
|
39
|
+
})
|
|
40
|
+
).toEqual([join("C:\\Users\\Alice", "AppData", "Local", "ms-playwright")]);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe("isPlaywrightChromiumInstalled", () => {
|
|
45
|
+
const skillDir = "/tmp/dev-browser";
|
|
46
|
+
|
|
47
|
+
it("detects chromium in the hermetic local browser directory", () => {
|
|
48
|
+
const hermeticRoot = join(skillDir, "node_modules", "playwright-core", ".local-browsers");
|
|
49
|
+
|
|
50
|
+
expect(
|
|
51
|
+
isPlaywrightChromiumInstalled({
|
|
52
|
+
skillDir,
|
|
53
|
+
platform: "win32",
|
|
54
|
+
env: { PLAYWRIGHT_BROWSERS_PATH: "0" },
|
|
55
|
+
exists: (path) => path === hermeticRoot,
|
|
56
|
+
readDir: () => ["chromium-1162"],
|
|
57
|
+
})
|
|
58
|
+
).toBe(true);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -12,6 +12,7 @@ export interface PackageManager {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export interface ChromiumInstallCheckOptions {
|
|
15
|
+
skillDir: string;
|
|
15
16
|
platform: NodeJS.Platform;
|
|
16
17
|
env: NodeJS.ProcessEnv;
|
|
17
18
|
exists: (path: string) => boolean;
|
|
@@ -66,21 +67,43 @@ export function getPlaywrightInstallCommand(manager: PackageManager): string {
|
|
|
66
67
|
return [manager.command, ...manager.args].join(" ");
|
|
67
68
|
}
|
|
68
69
|
|
|
70
|
+
function normalizePathForComparison(path: string): string {
|
|
71
|
+
return path.replaceAll("\\", "/").replace(/\/+/g, "/").toLowerCase();
|
|
72
|
+
}
|
|
73
|
+
|
|
69
74
|
export function getPlaywrightBrowserRoots({
|
|
75
|
+
skillDir,
|
|
70
76
|
platform,
|
|
71
77
|
env,
|
|
72
78
|
}: {
|
|
79
|
+
skillDir: string;
|
|
73
80
|
platform: NodeJS.Platform;
|
|
74
81
|
env: NodeJS.ProcessEnv;
|
|
75
82
|
}): string[] {
|
|
76
83
|
const explicitPath = env.PLAYWRIGHT_BROWSERS_PATH?.trim();
|
|
77
84
|
if (explicitPath) {
|
|
85
|
+
if (explicitPath === "0") {
|
|
86
|
+
return [join(skillDir, "node_modules", "playwright-core", ".local-browsers")];
|
|
87
|
+
}
|
|
78
88
|
return [explicitPath];
|
|
79
89
|
}
|
|
80
90
|
|
|
81
91
|
if (platform === "win32") {
|
|
82
|
-
const
|
|
83
|
-
|
|
92
|
+
const roots: string[] = [];
|
|
93
|
+
const localAppData = env.LOCALAPPDATA?.trim();
|
|
94
|
+
if (localAppData) {
|
|
95
|
+
roots.push(join(localAppData, "ms-playwright"));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const userProfile = env.USERPROFILE?.trim() ?? env.HOME?.trim();
|
|
99
|
+
if (userProfile) {
|
|
100
|
+
const fallbackRoot = join(userProfile, "AppData", "Local", "ms-playwright");
|
|
101
|
+
if (!roots.some((root) => normalizePathForComparison(root) === normalizePathForComparison(fallbackRoot))) {
|
|
102
|
+
roots.push(fallbackRoot);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return roots;
|
|
84
107
|
}
|
|
85
108
|
|
|
86
109
|
const home = env.HOME ?? env.USERPROFILE;
|
|
@@ -88,12 +111,13 @@ export function getPlaywrightBrowserRoots({
|
|
|
88
111
|
}
|
|
89
112
|
|
|
90
113
|
export function isPlaywrightChromiumInstalled({
|
|
114
|
+
skillDir,
|
|
91
115
|
platform,
|
|
92
116
|
env,
|
|
93
117
|
exists,
|
|
94
118
|
readDir,
|
|
95
119
|
}: ChromiumInstallCheckOptions): boolean {
|
|
96
|
-
for (const root of getPlaywrightBrowserRoots({ platform, env })) {
|
|
120
|
+
for (const root of getPlaywrightBrowserRoots({ skillDir, platform, env })) {
|
|
97
121
|
if (!exists(root)) {
|
|
98
122
|
continue;
|
|
99
123
|
}
|
|
@@ -35,9 +35,55 @@ python "<SKILL_DIR>/scripts/groksearch_entry.py" get_config_info [--no-test]
|
|
|
35
35
|
python "<SKILL_DIR>/scripts/groksearch_entry.py" toggle_builtin_tools --action on|off|status [--root /path/to/project]
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
##
|
|
38
|
+
## Tool Routing Policy
|
|
39
|
+
### Forced Replacement Rules
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
| Scenario | Disabled | Use Instead |
|
|
42
|
+
|----------|----------|-------------|
|
|
43
|
+
| Web Search | `WebSearch` | CLI `web_search` via `groksearch_entry.py` |
|
|
44
|
+
| Web Fetch | `WebFetch` | CLI `web_fetch` via `groksearch_entry.py` |
|
|
45
|
+
|
|
46
|
+
### Tool Capability Matrix
|
|
47
|
+
|
|
48
|
+
| Tool | Parameters | Output |
|
|
49
|
+
|------|------------|--------|
|
|
50
|
+
| `web_search` | `query`(required), `platform`/`min_results`/`max_results`/`model`/`extra_sources`(optional) | `[{title,url,description}]` |
|
|
51
|
+
| `web_fetch` | `url`(required), `out`/`fallback_grok`(optional) | Structured Markdown |
|
|
52
|
+
| `web_map` | `url`(required), `instructions`/`max_depth`/`max_breadth`/`limit`/`timeout`(optional) | JSON string |
|
|
53
|
+
| `get_config_info` | `no_test`(optional) | `{api_url,status,connection_test}` |
|
|
54
|
+
| `toggle_builtin_tools` | `action`(on/off/status), `root`(optional) | `{blocked,deny_list}` |
|
|
55
|
+
|
|
56
|
+
## Search Workflow
|
|
57
|
+
|
|
58
|
+
### Phase 1: Query Construction
|
|
59
|
+
- **Intent Recognition**: Broad search → `web_search` | Deep retrieval → `web_fetch`
|
|
60
|
+
- **Parameter Optimization**: Set `platform` for specific sources, adjust result counts; if you need broader source coverage, consider adding `--extra-sources 3`
|
|
61
|
+
|
|
62
|
+
### Phase 2: Search Execution
|
|
63
|
+
1. Start with `web_search` for structured summaries
|
|
64
|
+
2. Use `web_fetch` on key URLs if summaries insufficient
|
|
65
|
+
3. Retry with adjusted query if first round unsatisfactory
|
|
66
|
+
|
|
67
|
+
### Phase 3: Result Synthesis
|
|
68
|
+
1. Cross-reference multiple sources
|
|
69
|
+
2. **Must annotate source and date** for time-sensitive info
|
|
70
|
+
3. **Must include source URLs**: `Title [1](URL)`
|
|
71
|
+
|
|
72
|
+
## Error Handling
|
|
73
|
+
|
|
74
|
+
| Error | Recovery |
|
|
75
|
+
|-------|----------|
|
|
76
|
+
| Connection Failure | Run `get_config_info`, verify API URL/Key |
|
|
77
|
+
| No Results | Broaden search terms |
|
|
78
|
+
| Fetch Timeout | Try alternative sources |
|
|
79
|
+
| Tavily unavailable while using `--extra-sources` | Command keeps Grok results and prints a Tavily warning to stderr |
|
|
80
|
+
| Tavily extract failure | Use `--fallback-grok`, or inspect the Tavily warning/error message |
|
|
81
|
+
|
|
82
|
+
## Anti-Patterns
|
|
83
|
+
|
|
84
|
+
| Prohibited | Correct |
|
|
85
|
+
|------------|---------|
|
|
86
|
+
| No source citation | Include `Source [1](URL)` |
|
|
87
|
+
| Assume current repo has `skills/grok-search` | Check global skill directories under `$HOME` first, then project-level `.claude/.codex/.agents`, then call `<SKILL_DIR>/scripts/groksearch_entry.py` |
|
|
88
|
+
| Call `scripts/groksearch_cli.py` directly | Call `python scripts/groksearch_entry.py ...` |
|
|
89
|
+
| Use built-in WebSearch/WebFetch | Use GrokSearch CLI |
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# Resolve the installed skill directory for dev-browser.
|
|
3
|
-
# Outputs the resolved path to stdout. Exits 1 if not found.
|
|
4
|
-
SKILL_NAME="dev-browser"
|
|
5
|
-
SKILL_DIR=""
|
|
6
|
-
CANDIDATE_SUFFIXES=".agents/skills .claude/skills .codex/skills .config/agents/skills"
|
|
7
|
-
for base in \
|
|
8
|
-
"${CODEX_HOME:-$HOME/.codex}/skills" \
|
|
9
|
-
"$HOME/.agents/skills" \
|
|
10
|
-
"$HOME/.claude/skills" \
|
|
11
|
-
"$HOME/.config/agents/skills"
|
|
12
|
-
do
|
|
13
|
-
if [ -d "$base/$SKILL_NAME" ]; then
|
|
14
|
-
SKILL_DIR="$base/$SKILL_NAME"
|
|
15
|
-
break
|
|
16
|
-
fi
|
|
17
|
-
done
|
|
18
|
-
|
|
19
|
-
if [ -z "$SKILL_DIR" ]; then
|
|
20
|
-
SEARCH_DIR=$(pwd -P)
|
|
21
|
-
while :; do
|
|
22
|
-
for suffix in $CANDIDATE_SUFFIXES; do
|
|
23
|
-
if [ -d "$SEARCH_DIR/$suffix/$SKILL_NAME" ]; then
|
|
24
|
-
SKILL_DIR="$SEARCH_DIR/$suffix/$SKILL_NAME"
|
|
25
|
-
break 2
|
|
26
|
-
fi
|
|
27
|
-
done
|
|
28
|
-
[ "$SEARCH_DIR" = "/" ] && break
|
|
29
|
-
SEARCH_DIR=$(dirname "$SEARCH_DIR")
|
|
30
|
-
done
|
|
31
|
-
fi
|
|
32
|
-
|
|
33
|
-
[ -n "$SKILL_DIR" ] || { echo "Skill not found: $SKILL_NAME" >&2; exit 1; }
|
|
34
|
-
|
|
35
|
-
echo "$SKILL_DIR"
|