@fro.bot/systematic 1.0.0
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 +158 -0
- package/agents/research/framework-docs-researcher.md +19 -0
- package/agents/review/architecture-strategist.md +23 -0
- package/agents/review/code-simplicity-reviewer.md +30 -0
- package/agents/review/pattern-recognition-specialist.md +24 -0
- package/agents/review/performance-oracle.md +25 -0
- package/agents/review/security-sentinel.md +25 -0
- package/commands/agent-native-audit.md +277 -0
- package/commands/create-agent-skill.md +8 -0
- package/commands/deepen-plan.md +546 -0
- package/commands/lfg.md +19 -0
- package/commands/workflows/brainstorm.md +115 -0
- package/commands/workflows/compound.md +202 -0
- package/commands/workflows/plan.md +551 -0
- package/commands/workflows/review.md +514 -0
- package/commands/workflows/work.md +363 -0
- package/dist/cli.js +360 -0
- package/dist/index-v8dhd5s2.js +194 -0
- package/dist/index.js +297 -0
- package/package.json +69 -0
- package/skills/agent-browser/SKILL.md +223 -0
- package/skills/agent-native-architecture/SKILL.md +435 -0
- package/skills/agent-native-architecture/references/action-parity-discipline.md +409 -0
- package/skills/agent-native-architecture/references/agent-execution-patterns.md +467 -0
- package/skills/agent-native-architecture/references/agent-native-testing.md +582 -0
- package/skills/agent-native-architecture/references/architecture-patterns.md +478 -0
- package/skills/agent-native-architecture/references/dynamic-context-injection.md +338 -0
- package/skills/agent-native-architecture/references/files-universal-interface.md +301 -0
- package/skills/agent-native-architecture/references/from-primitives-to-domain-tools.md +359 -0
- package/skills/agent-native-architecture/references/mcp-tool-design.md +506 -0
- package/skills/agent-native-architecture/references/mobile-patterns.md +871 -0
- package/skills/agent-native-architecture/references/product-implications.md +443 -0
- package/skills/agent-native-architecture/references/refactoring-to-prompt-native.md +317 -0
- package/skills/agent-native-architecture/references/self-modification.md +269 -0
- package/skills/agent-native-architecture/references/shared-workspace-architecture.md +680 -0
- package/skills/agent-native-architecture/references/system-prompt-design.md +250 -0
- package/skills/brainstorming/SKILL.md +190 -0
- package/skills/compound-docs/SKILL.md +510 -0
- package/skills/compound-docs/assets/critical-pattern-template.md +34 -0
- package/skills/compound-docs/assets/resolution-template.md +93 -0
- package/skills/compound-docs/references/yaml-schema.md +65 -0
- package/skills/compound-docs/schema.yaml +176 -0
- package/skills/create-agent-skills/SKILL.md +299 -0
- package/skills/create-agent-skills/references/api-security.md +226 -0
- package/skills/create-agent-skills/references/be-clear-and-direct.md +531 -0
- package/skills/create-agent-skills/references/best-practices.md +404 -0
- package/skills/create-agent-skills/references/common-patterns.md +595 -0
- package/skills/create-agent-skills/references/core-principles.md +437 -0
- package/skills/create-agent-skills/references/executable-code.md +175 -0
- package/skills/create-agent-skills/references/iteration-and-testing.md +474 -0
- package/skills/create-agent-skills/references/official-spec.md +185 -0
- package/skills/create-agent-skills/references/recommended-structure.md +168 -0
- package/skills/create-agent-skills/references/skill-structure.md +372 -0
- package/skills/create-agent-skills/references/using-scripts.md +113 -0
- package/skills/create-agent-skills/references/using-templates.md +112 -0
- package/skills/create-agent-skills/references/workflows-and-validation.md +510 -0
- package/skills/create-agent-skills/templates/router-skill.md +73 -0
- package/skills/create-agent-skills/templates/simple-skill.md +33 -0
- package/skills/create-agent-skills/workflows/add-reference.md +96 -0
- package/skills/create-agent-skills/workflows/add-script.md +93 -0
- package/skills/create-agent-skills/workflows/add-template.md +74 -0
- package/skills/create-agent-skills/workflows/add-workflow.md +120 -0
- package/skills/create-agent-skills/workflows/audit-skill.md +138 -0
- package/skills/create-agent-skills/workflows/create-domain-expertise-skill.md +605 -0
- package/skills/create-agent-skills/workflows/create-new-skill.md +191 -0
- package/skills/create-agent-skills/workflows/get-guidance.md +121 -0
- package/skills/create-agent-skills/workflows/upgrade-to-router.md +161 -0
- package/skills/create-agent-skills/workflows/verify-skill.md +204 -0
- package/skills/file-todos/SKILL.md +251 -0
- package/skills/file-todos/assets/todo-template.md +155 -0
- package/skills/git-worktree/SKILL.md +302 -0
- package/skills/git-worktree/scripts/worktree-manager.sh +345 -0
- package/skills/using-systematic/SKILL.md +94 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import {
|
|
2
|
+
extractAgentFrontmatter,
|
|
3
|
+
extractCommandFrontmatter,
|
|
4
|
+
findAgentsInDir,
|
|
5
|
+
findCommandsInDir,
|
|
6
|
+
findSkillsInDir,
|
|
7
|
+
stripFrontmatter
|
|
8
|
+
} from "./index-v8dhd5s2.js";
|
|
9
|
+
|
|
10
|
+
// src/index.ts
|
|
11
|
+
import fs3 from "node:fs";
|
|
12
|
+
import os2 from "node:os";
|
|
13
|
+
import path2 from "node:path";
|
|
14
|
+
import { fileURLToPath } from "node:url";
|
|
15
|
+
import { tool } from "@opencode-ai/plugin/tool";
|
|
16
|
+
|
|
17
|
+
// src/lib/config-handler.ts
|
|
18
|
+
import fs2 from "node:fs";
|
|
19
|
+
|
|
20
|
+
// src/lib/config.ts
|
|
21
|
+
import fs from "node:fs";
|
|
22
|
+
import path from "node:path";
|
|
23
|
+
import os from "node:os";
|
|
24
|
+
import { parse as parseJsonc } from "jsonc-parser";
|
|
25
|
+
var DEFAULT_CONFIG = {
|
|
26
|
+
disabled_skills: [],
|
|
27
|
+
disabled_agents: [],
|
|
28
|
+
disabled_commands: [],
|
|
29
|
+
bootstrap: {
|
|
30
|
+
enabled: true
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
function loadJsoncFile(filePath) {
|
|
34
|
+
try {
|
|
35
|
+
if (!fs.existsSync(filePath))
|
|
36
|
+
return null;
|
|
37
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
38
|
+
return parseJsonc(content);
|
|
39
|
+
} catch {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function mergeArraysUnique(arr1, arr2) {
|
|
44
|
+
const set = new Set;
|
|
45
|
+
if (arr1)
|
|
46
|
+
arr1.forEach((item) => set.add(item));
|
|
47
|
+
if (arr2)
|
|
48
|
+
arr2.forEach((item) => set.add(item));
|
|
49
|
+
return Array.from(set);
|
|
50
|
+
}
|
|
51
|
+
function loadConfig(projectDir) {
|
|
52
|
+
const homeDir = os.homedir();
|
|
53
|
+
const userConfigPath = path.join(homeDir, ".config/opencode/systematic.json");
|
|
54
|
+
const projectConfigPath = path.join(projectDir, ".opencode/systematic.json");
|
|
55
|
+
const userConfig = loadJsoncFile(userConfigPath);
|
|
56
|
+
const projectConfig = loadJsoncFile(projectConfigPath);
|
|
57
|
+
const result = {
|
|
58
|
+
disabled_skills: mergeArraysUnique(mergeArraysUnique(DEFAULT_CONFIG.disabled_skills, userConfig?.disabled_skills), projectConfig?.disabled_skills),
|
|
59
|
+
disabled_agents: mergeArraysUnique(mergeArraysUnique(DEFAULT_CONFIG.disabled_agents, userConfig?.disabled_agents), projectConfig?.disabled_agents),
|
|
60
|
+
disabled_commands: mergeArraysUnique(mergeArraysUnique(DEFAULT_CONFIG.disabled_commands, userConfig?.disabled_commands), projectConfig?.disabled_commands),
|
|
61
|
+
bootstrap: {
|
|
62
|
+
...DEFAULT_CONFIG.bootstrap,
|
|
63
|
+
...userConfig?.bootstrap,
|
|
64
|
+
...projectConfig?.bootstrap
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// src/lib/config-handler.ts
|
|
71
|
+
function loadAgentAsConfig(agentInfo) {
|
|
72
|
+
try {
|
|
73
|
+
const content = fs2.readFileSync(agentInfo.file, "utf8");
|
|
74
|
+
const { name, description, prompt } = extractAgentFrontmatter(content);
|
|
75
|
+
return {
|
|
76
|
+
description: description || `${name || agentInfo.name} agent`,
|
|
77
|
+
prompt: prompt || stripFrontmatter(content)
|
|
78
|
+
};
|
|
79
|
+
} catch {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function loadCommandAsConfig(commandInfo) {
|
|
84
|
+
try {
|
|
85
|
+
const content = fs2.readFileSync(commandInfo.file, "utf8");
|
|
86
|
+
const { name, description } = extractCommandFrontmatter(content);
|
|
87
|
+
const cleanName = commandInfo.name.replace(/^\//, "");
|
|
88
|
+
return {
|
|
89
|
+
template: stripFrontmatter(content),
|
|
90
|
+
description: description || `${name || cleanName} command`
|
|
91
|
+
};
|
|
92
|
+
} catch {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function loadSkillAsCommand(skillInfo) {
|
|
97
|
+
try {
|
|
98
|
+
const content = fs2.readFileSync(skillInfo.skillFile, "utf8");
|
|
99
|
+
return {
|
|
100
|
+
template: stripFrontmatter(content),
|
|
101
|
+
description: skillInfo.description || `${skillInfo.name} skill`
|
|
102
|
+
};
|
|
103
|
+
} catch {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function collectAgents(dir, sourceType, disabledAgents) {
|
|
108
|
+
const agents = {};
|
|
109
|
+
const agentList = findAgentsInDir(dir, sourceType);
|
|
110
|
+
for (const agentInfo of agentList) {
|
|
111
|
+
if (disabledAgents.includes(agentInfo.name))
|
|
112
|
+
continue;
|
|
113
|
+
const config = loadAgentAsConfig(agentInfo);
|
|
114
|
+
if (config) {
|
|
115
|
+
agents[agentInfo.name] = config;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return agents;
|
|
119
|
+
}
|
|
120
|
+
function collectCommands(dir, sourceType, disabledCommands) {
|
|
121
|
+
const commands = {};
|
|
122
|
+
const commandList = findCommandsInDir(dir, sourceType);
|
|
123
|
+
for (const commandInfo of commandList) {
|
|
124
|
+
const cleanName = commandInfo.name.replace(/^\//, "");
|
|
125
|
+
if (disabledCommands.includes(cleanName))
|
|
126
|
+
continue;
|
|
127
|
+
const config = loadCommandAsConfig(commandInfo);
|
|
128
|
+
if (config) {
|
|
129
|
+
commands[cleanName] = config;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return commands;
|
|
133
|
+
}
|
|
134
|
+
function collectSkillsAsCommands(dir, sourceType, disabledSkills) {
|
|
135
|
+
const commands = {};
|
|
136
|
+
const skillList = findSkillsInDir(dir, sourceType, 3);
|
|
137
|
+
for (const skillInfo of skillList) {
|
|
138
|
+
if (disabledSkills.includes(skillInfo.name))
|
|
139
|
+
continue;
|
|
140
|
+
const config = loadSkillAsCommand(skillInfo);
|
|
141
|
+
if (config) {
|
|
142
|
+
commands[skillInfo.name] = config;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return commands;
|
|
146
|
+
}
|
|
147
|
+
function createConfigHandler(deps) {
|
|
148
|
+
const { directory, bundledSkillsDir, bundledAgentsDir, bundledCommandsDir } = deps;
|
|
149
|
+
return async (config) => {
|
|
150
|
+
const systematicConfig = loadConfig(directory);
|
|
151
|
+
const bundledAgents = collectAgents(bundledAgentsDir, "bundled", systematicConfig.disabled_agents);
|
|
152
|
+
const bundledCommands = collectCommands(bundledCommandsDir, "bundled", systematicConfig.disabled_commands);
|
|
153
|
+
const bundledSkills = collectSkillsAsCommands(bundledSkillsDir, "bundled", systematicConfig.disabled_skills);
|
|
154
|
+
const existingAgents = config.agent ?? {};
|
|
155
|
+
config.agent = {
|
|
156
|
+
...bundledAgents,
|
|
157
|
+
...existingAgents
|
|
158
|
+
};
|
|
159
|
+
const existingCommands = config.command ?? {};
|
|
160
|
+
config.command = {
|
|
161
|
+
...bundledCommands,
|
|
162
|
+
...bundledSkills,
|
|
163
|
+
...existingCommands
|
|
164
|
+
};
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// src/index.ts
|
|
169
|
+
var __dirname2 = path2.dirname(fileURLToPath(import.meta.url));
|
|
170
|
+
var packageRoot = path2.resolve(__dirname2, "..");
|
|
171
|
+
var bundledSkillsDir = path2.join(packageRoot, "skills");
|
|
172
|
+
var bundledAgentsDir = path2.join(packageRoot, "agents");
|
|
173
|
+
var bundledCommandsDir = path2.join(packageRoot, "commands");
|
|
174
|
+
function formatItemList(items, emptyMessage, header) {
|
|
175
|
+
if (items.length === 0)
|
|
176
|
+
return emptyMessage;
|
|
177
|
+
let output = header;
|
|
178
|
+
for (const item of items) {
|
|
179
|
+
output += `- ${item.name} (${item.sourceType})
|
|
180
|
+
`;
|
|
181
|
+
}
|
|
182
|
+
return output;
|
|
183
|
+
}
|
|
184
|
+
var getBootstrapContent = (config) => {
|
|
185
|
+
if (!config.bootstrap.enabled)
|
|
186
|
+
return null;
|
|
187
|
+
if (config.bootstrap.file) {
|
|
188
|
+
const customPath = config.bootstrap.file.startsWith("~/") ? path2.join(os2.homedir(), config.bootstrap.file.slice(2)) : config.bootstrap.file;
|
|
189
|
+
if (fs3.existsSync(customPath)) {
|
|
190
|
+
return fs3.readFileSync(customPath, "utf8");
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
const usingSystematicPath = path2.join(bundledSkillsDir, "using-systematic/SKILL.md");
|
|
194
|
+
if (!fs3.existsSync(usingSystematicPath))
|
|
195
|
+
return null;
|
|
196
|
+
const fullContent = fs3.readFileSync(usingSystematicPath, "utf8");
|
|
197
|
+
const content = stripFrontmatter(fullContent);
|
|
198
|
+
const toolMapping = `**Tool Mapping for OpenCode:**
|
|
199
|
+
When skills reference tools you don't have, substitute OpenCode equivalents:
|
|
200
|
+
- \`TodoWrite\` → \`update_plan\`
|
|
201
|
+
- \`Task\` tool with subagents → Use OpenCode's subagent system (@mention)
|
|
202
|
+
- \`Skill\` tool → OpenCode's native \`skill\` tool
|
|
203
|
+
- \`Read\`, \`Write\`, \`Edit\`, \`Bash\` → Your native tools
|
|
204
|
+
|
|
205
|
+
**Skills naming:**
|
|
206
|
+
- Bundled skills use the \`systematic:\` prefix (e.g., \`systematic:brainstorming\`)
|
|
207
|
+
- Skills can also be invoked without prefix if unambiguous
|
|
208
|
+
|
|
209
|
+
**Skills location:**
|
|
210
|
+
Bundled skills are in \`${bundledSkillsDir}/\`
|
|
211
|
+
Use \`systematic_find_skills\` to list all available skills.`;
|
|
212
|
+
return `<SYSTEMATIC_WORKFLOWS>
|
|
213
|
+
You have access to structured engineering workflows via the systematic plugin.
|
|
214
|
+
|
|
215
|
+
**IMPORTANT: The using-systematic skill content is included below. It is ALREADY LOADED - you are currently following it. Do NOT use the skill tool to load "using-systematic" again - that would be redundant.**
|
|
216
|
+
|
|
217
|
+
${content}
|
|
218
|
+
|
|
219
|
+
${toolMapping}
|
|
220
|
+
</SYSTEMATIC_WORKFLOWS>`;
|
|
221
|
+
};
|
|
222
|
+
var SystematicPlugin = async ({ client, directory }) => {
|
|
223
|
+
const config = loadConfig(directory);
|
|
224
|
+
const configHandler = createConfigHandler({
|
|
225
|
+
directory,
|
|
226
|
+
bundledSkillsDir,
|
|
227
|
+
bundledAgentsDir,
|
|
228
|
+
bundledCommandsDir
|
|
229
|
+
});
|
|
230
|
+
return {
|
|
231
|
+
config: configHandler,
|
|
232
|
+
tool: {
|
|
233
|
+
systematic_find_skills: tool({
|
|
234
|
+
description: "List all available skills in the bundled skill library.",
|
|
235
|
+
args: {},
|
|
236
|
+
execute: async () => {
|
|
237
|
+
const bundledSkills = findSkillsInDir(bundledSkillsDir, "bundled", 3);
|
|
238
|
+
const skills = bundledSkills.filter((s) => !config.disabled_skills.includes(s.name)).sort((a, b) => a.name.localeCompare(b.name));
|
|
239
|
+
if (skills.length === 0) {
|
|
240
|
+
return "No skills available. Skills are bundled with the systematic plugin.";
|
|
241
|
+
}
|
|
242
|
+
let output = `Available skills:
|
|
243
|
+
|
|
244
|
+
`;
|
|
245
|
+
for (const skill of skills) {
|
|
246
|
+
output += `systematic:${skill.name}
|
|
247
|
+
`;
|
|
248
|
+
if (skill.description) {
|
|
249
|
+
output += ` ${skill.description}
|
|
250
|
+
`;
|
|
251
|
+
}
|
|
252
|
+
output += ` Directory: ${skill.path}
|
|
253
|
+
|
|
254
|
+
`;
|
|
255
|
+
}
|
|
256
|
+
return output.trim();
|
|
257
|
+
}
|
|
258
|
+
}),
|
|
259
|
+
systematic_find_agents: tool({
|
|
260
|
+
description: "List all available review agents.",
|
|
261
|
+
args: {},
|
|
262
|
+
execute: async () => {
|
|
263
|
+
const bundledAgents = findAgentsInDir(bundledAgentsDir, "bundled");
|
|
264
|
+
const agents = bundledAgents.filter((a) => !config.disabled_agents.includes(a.name)).sort((a, b) => a.name.localeCompare(b.name));
|
|
265
|
+
return formatItemList(agents, "No agents available.", `Available agents:
|
|
266
|
+
|
|
267
|
+
`);
|
|
268
|
+
}
|
|
269
|
+
}),
|
|
270
|
+
systematic_find_commands: tool({
|
|
271
|
+
description: "List all available commands.",
|
|
272
|
+
args: {},
|
|
273
|
+
execute: async () => {
|
|
274
|
+
const bundledCommands = findCommandsInDir(bundledCommandsDir, "bundled");
|
|
275
|
+
const commands = bundledCommands.filter((c) => !config.disabled_commands.includes(c.name.replace(/^\//, ""))).sort((a, b) => a.name.localeCompare(b.name));
|
|
276
|
+
return formatItemList(commands, "No commands available.", `Available commands:
|
|
277
|
+
|
|
278
|
+
`);
|
|
279
|
+
}
|
|
280
|
+
})
|
|
281
|
+
},
|
|
282
|
+
"experimental.chat.system.transform": async (_input, output) => {
|
|
283
|
+
const content = getBootstrapContent(config);
|
|
284
|
+
if (content) {
|
|
285
|
+
if (!output.system) {
|
|
286
|
+
output.system = [];
|
|
287
|
+
}
|
|
288
|
+
output.system.push(content);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
};
|
|
293
|
+
var src_default = SystematicPlugin;
|
|
294
|
+
export {
|
|
295
|
+
src_default as default,
|
|
296
|
+
SystematicPlugin
|
|
297
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fro.bot/systematic",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Structured engineering workflows for OpenCode",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"systematic": "./dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"skills",
|
|
19
|
+
"agents",
|
|
20
|
+
"commands"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "bun build src/index.ts src/cli.ts --outdir dist --target node --format esm --splitting --external @opencode-ai/plugin/tool --external jsonc-parser",
|
|
24
|
+
"dev": "bun --watch src/index.ts",
|
|
25
|
+
"test": "bun test tests/unit",
|
|
26
|
+
"test:integration": "bun test tests/integration",
|
|
27
|
+
"test:all": "bun test",
|
|
28
|
+
"typecheck": "tsc --noEmit",
|
|
29
|
+
"lint": "biome check .",
|
|
30
|
+
"prepublishOnly": "bun run build && bun run test"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"opencode",
|
|
34
|
+
"plugin",
|
|
35
|
+
"ai",
|
|
36
|
+
"workflow",
|
|
37
|
+
"engineering"
|
|
38
|
+
],
|
|
39
|
+
"author": "Marcus R. Brown",
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "https://github.com/marcusrbrown/systematic.git"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=18"
|
|
47
|
+
},
|
|
48
|
+
"peerDependencies": {
|
|
49
|
+
"@opencode-ai/plugin": "^1.1.30"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@biomejs/biome": "^1.9.0",
|
|
53
|
+
"@opencode-ai/plugin": "^1.1.30",
|
|
54
|
+
"@types/bun": "latest",
|
|
55
|
+
"@types/node": "^22.0.0",
|
|
56
|
+
"conventional-changelog-conventionalcommits": "^9.0.0",
|
|
57
|
+
"markdownlint-cli": "^0.47.0",
|
|
58
|
+
"semantic-release": "^25.0.0",
|
|
59
|
+
"semantic-release-export-data": "^1.2.0",
|
|
60
|
+
"typescript": "^5.7.0"
|
|
61
|
+
},
|
|
62
|
+
"dependencies": {
|
|
63
|
+
"jsonc-parser": "^3.3.0"
|
|
64
|
+
},
|
|
65
|
+
"publishConfig": {
|
|
66
|
+
"access": "public",
|
|
67
|
+
"provenance": true
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agent-browser
|
|
3
|
+
description: Browser automation using Vercel's agent-browser CLI. Use when you need to interact with web pages, fill forms, take screenshots, or scrape data. Alternative to Playwright MCP - uses Bash commands with ref-based element selection. Triggers on "browse website", "fill form", "click button", "take screenshot", "scrape page", "web automation".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# agent-browser: CLI Browser Automation
|
|
7
|
+
|
|
8
|
+
Vercel's headless browser automation CLI designed for AI agents. Uses ref-based selection (@e1, @e2) from accessibility snapshots.
|
|
9
|
+
|
|
10
|
+
## Setup Check
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
# Check installation
|
|
14
|
+
command -v agent-browser >/dev/null 2>&1 && echo "Installed" || echo "NOT INSTALLED - run: npm install -g agent-browser && agent-browser install"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Install if needed
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install -g agent-browser
|
|
21
|
+
agent-browser install # Downloads Chromium
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Core Workflow
|
|
25
|
+
|
|
26
|
+
**The snapshot + ref pattern is optimal for LLMs:**
|
|
27
|
+
|
|
28
|
+
1. **Navigate** to URL
|
|
29
|
+
2. **Snapshot** to get interactive elements with refs
|
|
30
|
+
3. **Interact** using refs (@e1, @e2, etc.)
|
|
31
|
+
4. **Re-snapshot** after navigation or DOM changes
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# Step 1: Open URL
|
|
35
|
+
agent-browser open https://example.com
|
|
36
|
+
|
|
37
|
+
# Step 2: Get interactive elements with refs
|
|
38
|
+
agent-browser snapshot -i --json
|
|
39
|
+
|
|
40
|
+
# Step 3: Interact using refs
|
|
41
|
+
agent-browser click @e1
|
|
42
|
+
agent-browser fill @e2 "search query"
|
|
43
|
+
|
|
44
|
+
# Step 4: Re-snapshot after changes
|
|
45
|
+
agent-browser snapshot -i
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Key Commands
|
|
49
|
+
|
|
50
|
+
### Navigation
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
agent-browser open <url> # Navigate to URL
|
|
54
|
+
agent-browser back # Go back
|
|
55
|
+
agent-browser forward # Go forward
|
|
56
|
+
agent-browser reload # Reload page
|
|
57
|
+
agent-browser close # Close browser
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Snapshots (Essential for AI)
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
agent-browser snapshot # Full accessibility tree
|
|
64
|
+
agent-browser snapshot -i # Interactive elements only (recommended)
|
|
65
|
+
agent-browser snapshot -i --json # JSON output for parsing
|
|
66
|
+
agent-browser snapshot -c # Compact (remove empty elements)
|
|
67
|
+
agent-browser snapshot -d 3 # Limit depth
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Interactions
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
agent-browser click @e1 # Click element
|
|
74
|
+
agent-browser dblclick @e1 # Double-click
|
|
75
|
+
agent-browser fill @e1 "text" # Clear and fill input
|
|
76
|
+
agent-browser type @e1 "text" # Type without clearing
|
|
77
|
+
agent-browser press Enter # Press key
|
|
78
|
+
agent-browser hover @e1 # Hover element
|
|
79
|
+
agent-browser check @e1 # Check checkbox
|
|
80
|
+
agent-browser uncheck @e1 # Uncheck checkbox
|
|
81
|
+
agent-browser select @e1 "option" # Select dropdown option
|
|
82
|
+
agent-browser scroll down 500 # Scroll (up/down/left/right)
|
|
83
|
+
agent-browser scrollintoview @e1 # Scroll element into view
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Get Information
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
agent-browser get text @e1 # Get element text
|
|
90
|
+
agent-browser get html @e1 # Get element HTML
|
|
91
|
+
agent-browser get value @e1 # Get input value
|
|
92
|
+
agent-browser get attr href @e1 # Get attribute
|
|
93
|
+
agent-browser get title # Get page title
|
|
94
|
+
agent-browser get url # Get current URL
|
|
95
|
+
agent-browser get count "button" # Count matching elements
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Screenshots & PDFs
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
agent-browser screenshot # Viewport screenshot
|
|
102
|
+
agent-browser screenshot --full # Full page
|
|
103
|
+
agent-browser screenshot output.png # Save to file
|
|
104
|
+
agent-browser screenshot --full output.png # Full page to file
|
|
105
|
+
agent-browser pdf output.pdf # Save as PDF
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Wait
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
agent-browser wait @e1 # Wait for element
|
|
112
|
+
agent-browser wait 2000 # Wait milliseconds
|
|
113
|
+
agent-browser wait "text" # Wait for text to appear
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Semantic Locators (Alternative to Refs)
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
agent-browser find role button click --name "Submit"
|
|
120
|
+
agent-browser find text "Sign up" click
|
|
121
|
+
agent-browser find label "Email" fill "user@example.com"
|
|
122
|
+
agent-browser find placeholder "Search..." fill "query"
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Sessions (Parallel Browsers)
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# Run multiple independent browser sessions
|
|
129
|
+
agent-browser --session browser1 open https://site1.com
|
|
130
|
+
agent-browser --session browser2 open https://site2.com
|
|
131
|
+
|
|
132
|
+
# List active sessions
|
|
133
|
+
agent-browser session list
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Examples
|
|
137
|
+
|
|
138
|
+
### Login Flow
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
agent-browser open https://app.example.com/login
|
|
142
|
+
agent-browser snapshot -i
|
|
143
|
+
# Output shows: textbox "Email" [ref=e1], textbox "Password" [ref=e2], button "Sign in" [ref=e3]
|
|
144
|
+
agent-browser fill @e1 "user@example.com"
|
|
145
|
+
agent-browser fill @e2 "password123"
|
|
146
|
+
agent-browser click @e3
|
|
147
|
+
agent-browser wait 2000
|
|
148
|
+
agent-browser snapshot -i # Verify logged in
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Search and Extract
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
agent-browser open https://news.ycombinator.com
|
|
155
|
+
agent-browser snapshot -i --json
|
|
156
|
+
# Parse JSON to find story links
|
|
157
|
+
agent-browser get text @e12 # Get headline text
|
|
158
|
+
agent-browser click @e12 # Click to open story
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Form Filling
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
agent-browser open https://forms.example.com
|
|
165
|
+
agent-browser snapshot -i
|
|
166
|
+
agent-browser fill @e1 "John Doe"
|
|
167
|
+
agent-browser fill @e2 "john@example.com"
|
|
168
|
+
agent-browser select @e3 "United States"
|
|
169
|
+
agent-browser check @e4 # Agree to terms
|
|
170
|
+
agent-browser click @e5 # Submit button
|
|
171
|
+
agent-browser screenshot confirmation.png
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Debug Mode
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
# Run with visible browser window
|
|
178
|
+
agent-browser --headed open https://example.com
|
|
179
|
+
agent-browser --headed snapshot -i
|
|
180
|
+
agent-browser --headed click @e1
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## JSON Output
|
|
184
|
+
|
|
185
|
+
Add `--json` for structured output:
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
agent-browser snapshot -i --json
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
```json
|
|
193
|
+
{
|
|
194
|
+
"success": true,
|
|
195
|
+
"data": {
|
|
196
|
+
"refs": {
|
|
197
|
+
"e1": {"name": "Submit", "role": "button"},
|
|
198
|
+
"e2": {"name": "Email", "role": "textbox"}
|
|
199
|
+
},
|
|
200
|
+
"snapshot": "- button \"Submit\" [ref=e1]\n- textbox \"Email\" [ref=e2]"
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## vs Playwright MCP
|
|
206
|
+
|
|
207
|
+
| Feature | agent-browser (CLI) | Playwright MCP |
|
|
208
|
+
|---------|---------------------|----------------|
|
|
209
|
+
| Interface | Bash commands | MCP tools |
|
|
210
|
+
| Selection | Refs (@e1) | Refs (e1) |
|
|
211
|
+
| Output | Text/JSON | Tool responses |
|
|
212
|
+
| Parallel | Sessions | Tabs |
|
|
213
|
+
| Best for | Quick automation | Tool integration |
|
|
214
|
+
|
|
215
|
+
Use agent-browser when:
|
|
216
|
+
- You prefer Bash-based workflows
|
|
217
|
+
- You want simpler CLI commands
|
|
218
|
+
- You need quick one-off automation
|
|
219
|
+
|
|
220
|
+
Use Playwright MCP when:
|
|
221
|
+
- You need deep MCP tool integration
|
|
222
|
+
- You want tool-based responses
|
|
223
|
+
- You're building complex automation
|