abelworkflow 0.6.2 → 0.6.4
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/.gitignore +1 -0
- package/README.md +30 -0
- package/commands/oc/plan.md +1 -1
- package/commands/oc/research.md +4 -4
- package/lib/cli.mjs +2 -2
- package/lib/templates/codex/config-base.toml +1 -1
- package/package.json +4 -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/.gitignore
CHANGED
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/commands/oc/plan.md
CHANGED
|
@@ -77,7 +77,7 @@ argument-hint: [change_name]
|
|
|
77
77
|
- Use `openspec list --specs` to check for conflicts with existing specifications.
|
|
78
78
|
- Search existing patterns with `rg -n "INVARIANT:|PROPERTY:|Constraint:" openspec/` before defining new ones.
|
|
79
79
|
- For complex proposals, consider running steps 2-4 iteratively on sub-components.
|
|
80
|
-
-
|
|
80
|
+
- Ask the user directly for ANY ambiguity—do not assume or guess.
|
|
81
81
|
|
|
82
82
|
**Exit Criteria**
|
|
83
83
|
A proposal is ready to exit the Plan phase only when:
|
package/commands/oc/research.md
CHANGED
|
@@ -26,7 +26,7 @@ Produce constraint sets that narrow the solution space, plus measurable success
|
|
|
26
26
|
|
|
27
27
|
## Phase 0 — Requirement Intake Gate (MANDATORY)
|
|
28
28
|
- **MUST** confirm the user’s requirement exists and is clear **before** any research/action.
|
|
29
|
-
- If missing/unclear, **MUST**
|
|
29
|
+
- If missing/unclear, **MUST** ask the user directly in a concise grouped message to collect: goal, in-scope area, top scenarios, non-goals, known constraints, success signals.
|
|
30
30
|
- **MUST NOT** run `/opsx:new`, any codebase retrieval, spawn subagents, or generate artifacts until the user confirms a brief requirement summary.
|
|
31
31
|
|
|
32
32
|
---
|
|
@@ -97,7 +97,7 @@ All explore subagents MUST return valid JSON using this schema:
|
|
|
97
97
|
|
|
98
98
|
## Phase 7 — User Interaction for Ambiguity Resolution
|
|
99
99
|
- Compile prioritized list of open questions from aggregated reports.
|
|
100
|
-
-
|
|
100
|
+
- Present questions directly to the user in a concise grouped message:
|
|
101
101
|
* Group related questions together.
|
|
102
102
|
* Provide context for each question.
|
|
103
103
|
* Suggest default answers when applicable.
|
|
@@ -122,5 +122,5 @@ All explore subagents MUST return valid JSON using this schema:
|
|
|
122
122
|
- `openspec status --change <name>` - Check artifact completion status
|
|
123
123
|
- `openspec instructions proposal --change <name>` - Get proposal instructions
|
|
124
124
|
- Validate subagent outputs conform to template before aggregation.
|
|
125
|
-
-
|
|
126
|
-
<!-- OC:RESEARCH:END -->
|
|
125
|
+
- Ask the user directly for ANY ambiguity—do not assume or guess.
|
|
126
|
+
<!-- OC:RESEARCH:END -->
|
package/lib/cli.mjs
CHANGED
|
@@ -1871,8 +1871,8 @@ function buildCodexConfigContent(currentContent, {
|
|
|
1871
1871
|
content = mergeCodexTemplateDefaults(content, effectiveTemplateContent);
|
|
1872
1872
|
}
|
|
1873
1873
|
const lineEnding = detectLineEnding(content);
|
|
1874
|
-
if (includeSubagentDefaults && readTopLevelTomlString(content, "approvals_reviewer") === "
|
|
1875
|
-
content = updateTopLevelTomlField(content, "approvals_reviewer", "
|
|
1874
|
+
if (includeSubagentDefaults && readTopLevelTomlString(content, "approvals_reviewer") === "reviewer") {
|
|
1875
|
+
content = updateTopLevelTomlField(content, "approvals_reviewer", "guardian_subagent");
|
|
1876
1876
|
}
|
|
1877
1877
|
content = updateTopLevelTomlField(content, "model_provider", providerId);
|
|
1878
1878
|
content = updateTopLevelTomlField(content, "preferred_auth_method", "apikey");
|
|
@@ -2,7 +2,7 @@ personality = "pragmatic"
|
|
|
2
2
|
model_provider = "abelworkflow"
|
|
3
3
|
disable_response_storage = true
|
|
4
4
|
preferred_auth_method = "apikey"
|
|
5
|
-
approvals_reviewer = "
|
|
5
|
+
approvals_reviewer = "guardian_subagent"
|
|
6
6
|
approval_policy = "on-request"
|
|
7
7
|
sandbox_mode = "workspace-write"
|
|
8
8
|
service_tier = "fast"
|
package/package.json
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "abelworkflow",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.4",
|
|
4
4
|
"description": "Install AbelWorkflow into ~/.agents and create Claude/Codex symlinks.",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test:contracts": "node --test test/runtime-doc-contracts.test.mjs"
|
|
8
|
+
},
|
|
6
9
|
"bin": {
|
|
7
10
|
"abelworkflow": "bin/abelworkflow.mjs"
|
|
8
11
|
},
|
|
@@ -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"
|