abelworkflow 1.2.4 → 1.3.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.
Files changed (63) hide show
  1. package/README.md +26 -25
  2. package/extensions/gpt-responses-compat.ts +1 -1
  3. package/lib/cli/main.mjs +18 -86
  4. package/lib/cli/pi.mjs +43 -0
  5. package/lib/cli/prompts.mjs +3 -3
  6. package/lib/installer/assets.mjs +35 -31
  7. package/lib/installer/install.mjs +29 -9
  8. package/lib/installer/links.mjs +97 -84
  9. package/lib/paths.mjs +0 -2
  10. package/lib/providers/claude.mjs +14 -3
  11. package/lib/providers/codex.mjs +14 -9
  12. package/lib/providers/pi.mjs +61 -68
  13. package/lib/providers/skills.mjs +22 -22
  14. package/lib/providers/url.mjs +32 -1
  15. package/lib/templates/codex/agents/default.toml +16 -54
  16. package/lib/templates/codex/agents/explorer.toml +25 -52
  17. package/lib/templates/codex/agents/planner.toml +23 -77
  18. package/lib/templates/codex/agents/reviewer.toml +16 -62
  19. package/lib/templates/codex/agents/worker.toml +30 -64
  20. package/lib/templates/codex/config-base.toml +0 -6
  21. package/lib/templates/{workflow/gitignore.template → gitignore.template} +0 -3
  22. package/lib/tools/cli-installer.mjs +40 -12
  23. package/package.json +13 -18
  24. package/lib/templates/workflow/AGENTS.md +0 -50
  25. package/lib/templates/workflow/commands/abel-design.md +0 -175
  26. package/lib/templates/workflow/commands/abel-diagnose.md +0 -63
  27. package/lib/templates/workflow/commands/abel-implement.md +0 -170
  28. package/lib/templates/workflow/commands/abel-init.md +0 -25
  29. package/skills/dev-browser/SKILL.md +0 -281
  30. package/skills/dev-browser/dist/scripts/start.d.ts +0 -1
  31. package/skills/dev-browser/dist/scripts/start.js +0 -90
  32. package/skills/dev-browser/dist/src/client.d.ts +0 -92
  33. package/skills/dev-browser/dist/src/client.js +0 -310
  34. package/skills/dev-browser/dist/src/entrypoint.d.ts +0 -29
  35. package/skills/dev-browser/dist/src/entrypoint.js +0 -113
  36. package/skills/dev-browser/dist/src/index.d.ts +0 -3
  37. package/skills/dev-browser/dist/src/index.js +0 -1
  38. package/skills/dev-browser/dist/src/page-api.d.ts +0 -24
  39. package/skills/dev-browser/dist/src/page-api.js +0 -103
  40. package/skills/dev-browser/dist/src/relay.d.ts +0 -26
  41. package/skills/dev-browser/dist/src/relay.js +0 -567
  42. package/skills/dev-browser/dist/src/runtime.d.ts +0 -34
  43. package/skills/dev-browser/dist/src/runtime.js +0 -44
  44. package/skills/dev-browser/dist/src/snapshot/browser-script.d.ts +0 -22
  45. package/skills/dev-browser/dist/src/snapshot/browser-script.js +0 -868
  46. package/skills/dev-browser/dist/src/snapshot/index.d.ts +0 -13
  47. package/skills/dev-browser/dist/src/snapshot/index.js +0 -13
  48. package/skills/dev-browser/dist/src/snapshot/inject.d.ts +0 -12
  49. package/skills/dev-browser/dist/src/snapshot/inject.js +0 -12
  50. package/skills/dev-browser/dist/src/standalone.d.ts +0 -31
  51. package/skills/dev-browser/dist/src/standalone.js +0 -173
  52. package/skills/dev-browser/dist/src/startup.d.ts +0 -46
  53. package/skills/dev-browser/dist/src/startup.js +0 -77
  54. package/skills/dev-browser/dist/src/target-registry.d.ts +0 -28
  55. package/skills/dev-browser/dist/src/target-registry.js +0 -134
  56. package/skills/dev-browser/dist/src/types.d.ts +0 -26
  57. package/skills/dev-browser/dist/src/types.js +0 -1
  58. package/skills/dev-browser/package-lock.json +0 -1545
  59. package/skills/dev-browser/package.json +0 -35
  60. package/skills/dev-browser/references/scraping.md +0 -144
  61. package/skills/git-commit/SKILL.md +0 -124
  62. package/skills/time/SKILL.md +0 -119
  63. package/skills/time/scripts/time_cli.py +0 -143
@@ -1,281 +0,0 @@
1
- ---
2
- name: dev-browser
3
- description: Browser automation with page state shared while the server process runs. Use when users ask to navigate websites, fill forms, take screenshots, extract web data, test web apps, or automate browser workflows. Trigger phrases include "go to [url]", "click on", "fill out the form", "take a screenshot", "scrape", "automate", "test the website", "log into", or any browser interaction request.
4
- ---
5
-
6
- # Dev Browser Skill
7
-
8
- Browser automation that maintains page state across script executions while the server process runs. Write small, focused scripts to accomplish tasks incrementally.
9
-
10
- ## Choosing Your Approach
11
-
12
- - **Local/source-available sites**: Read the source code first to write selectors directly
13
- - **Unknown page layouts**: Use `getAISnapshot()` to discover elements and `selectSnapshotRef()` to interact with them
14
- - **Visual feedback**: Take screenshots to see what the user sees
15
-
16
- ## Setup
17
-
18
- Two supported startup modes are available on **Linux** and **native Windows**. Run the following commands from the installed `dev-browser` skill directory. Bash, Git Bash, and WSL are not required.
19
-
20
- Startup never installs packages or browsers and treats the skill directory as read-only. If a preflight reports missing dependencies, run its explicit setup command yourself. Typical setup commands from the installed skill directory are:
21
-
22
- ```text
23
- npm ci --omit=dev
24
- node "node_modules/playwright/cli.js" install chromium
25
- ```
26
-
27
- The Playwright command is required only for standalone mode. Startup does not download Chromium automatically.
28
-
29
- ### Standalone Mode (Default)
30
-
31
- Launches a new Chromium browser for fresh automation sessions.
32
-
33
- ```text
34
- node dist/scripts/start.js standalone
35
- ```
36
-
37
- Add `--headless` if needed:
38
-
39
- ```text
40
- node dist/scripts/start.js standalone --headless
41
- ```
42
-
43
- Wait for the stable readiness line `Ready` before running scripts.
44
-
45
- ### Extension Mode
46
-
47
- Connects to the user's existing Chrome browser. Use this when:
48
-
49
- - The user is already logged into sites and wants you to do things behind an authed experience that isn't local dev.
50
- - The user asks you to use the extension.
51
-
52
- Start the relay server with:
53
-
54
- ```text
55
- node dist/scripts/start.js extension
56
- ```
57
-
58
- Wait for `Waiting for extension to connect...`. Once the browser extension attaches, the relay logs `Extension connected`.
59
-
60
- If the extension hasn't connected yet, tell the user to launch and activate it. Download link: https://github.com/SawyerHood/dev-browser/releases
61
-
62
- ## Support Matrix
63
-
64
- | Mode | Linux | Native Windows | Readiness signal | Notes |
65
- |------|-------|----------------|------------------|-------|
66
- | standalone mode | Supported | Supported | `Ready` | Uses a process-owned temporary Chromium profile and cleans it on exit |
67
- | extension mode | Supported | Supported | `Waiting for extension to connect...` then `Extension connected` | Requires the external browser extension to attach |
68
-
69
- ## Verification Checklist
70
-
71
- - Start `standalone mode` with `node dist/scripts/start.js standalone`
72
- - Observe the readiness line `Ready`
73
- - Connect with `connect()` and create a named page
74
- - Start `extension mode` with `node dist/scripts/start.js extension`
75
- - Observe `Waiting for extension to connect...`
76
- - Attach the browser extension and confirm `Extension connected`
77
-
78
- ## Known Differences
79
-
80
- - `standalone mode` owns a temporary Chromium profile only for the server process lifetime and cleans it on exit.
81
- - `extension mode` depends on the external browser extension and the user's existing Chrome session.
82
- - Extension mode rejects viewport requests with HTTP 400; viewport sizing is supported only in standalone mode.
83
- - In `extension mode`, relay readiness means the server is waiting for the extension; it does not imply browser control is available until `Extension connected` appears.
84
- - `standalone mode` is the default path for deterministic local automation; `extension mode` is for working inside an already-authenticated browser.
85
-
86
- ## Server Boundary
87
-
88
- - Both server modes and their direct APIs accept only loopback hosts: `localhost`, IPv4 loopback addresses in `127.0.0.0/8`, and `::1` (bracketed IPv6 is accepted in CLI input).
89
- - Wildcard, LAN, and other hosts are rejected. This loopback-only binding is the primary access boundary.
90
- - Origin checks are defense-in-depth, not authentication.
91
-
92
- - State-changing `/pages` requests accept only originless JSON clients; browser-origin and non-JSON mutations are rejected before backend calls.
93
- - `/cdp` accepts only originless WebSocket clients, which is the normal behavior of the Node client. Browser pages always send an `Origin` and are rejected.
94
- - `/extension` accepts originless protocol clients and valid `chrome-extension://` origins. HTTP(S), `null`, malformed, and other origins are rejected.
95
- - Rejected sockets close with WebSocket policy code `1008` before they can own a client ID, replace the extension, or route buffered messages.
96
-
97
- ## Non-goal Environments
98
-
99
- - `WSL` and `Git Bash` are not part of the supported Windows path for this skill.
100
- - Native Windows support means PowerShell / Command Prompt can use the documented entrypoints directly.
101
- - If a user runs inside WSL or Git Bash, treat that as a separate environment rather than the official Windows support contract.
102
-
103
- ## Writing Scripts
104
-
105
- Treat the installed `dev-browser` skill directory as read-only. Store scripts and artifacts in the OS temporary directory or task workspace, never inside the skill directory, and delete files you created when the task ends.
106
-
107
- External scripts cannot use package self-resolution, so pass the installed skill directory as the first argument and import its compiled client by file URL. Example:
108
-
109
- ```javascript
110
- import { tmpdir } from "node:os";
111
- import { join } from "node:path";
112
- import { pathToFileURL } from "node:url";
113
-
114
- const skillDir = process.argv[2];
115
- if (!skillDir) throw new Error("Pass the installed dev-browser skill directory");
116
- const { connect, waitForPageLoad } = await import(
117
- pathToFileURL(join(skillDir, "dist", "src", "client.js")).href
118
- );
119
-
120
- const client = await connect();
121
- const page = await client.page("example", { viewport: { width: 1920, height: 1080 } });
122
-
123
- await page.goto("https://example.com");
124
- await waitForPageLoad(page);
125
- const screenshotPath = join(tmpdir(), "dev-browser-screenshot.png");
126
- await page.screenshot({ path: screenshotPath });
127
-
128
- console.log({ title: await page.title(), url: page.url(), screenshotPath });
129
- await client.disconnect();
130
- ```
131
-
132
- This invocation works in Linux shells, PowerShell, and Command Prompt when the two paths are quoted:
133
-
134
- ```text
135
- node "PATH_TO_SCRIPT.mjs" "PATH_TO_INSTALLED_DEV_BROWSER"
136
- ```
137
-
138
- ### Key Principles
139
-
140
- 1. **Small scripts**: Each script does ONE thing (navigate, click, fill, check)
141
- 2. **Evaluate state**: Log/return state at the end to decide next steps
142
- 3. **Descriptive page names**: Use `"checkout"`, `"login"`, not `"main"`
143
- 4. **Disconnect to exit**: `await client.disconnect()` - pages persist while the server process runs
144
- 5. **Plain JS in evaluate**: `page.evaluate()` runs in browser - no TypeScript syntax
145
-
146
- ## Workflow Loop
147
-
148
- Follow this pattern for complex tasks:
149
-
150
- 1. **Write a script** to perform one action
151
- 2. **Run it** and observe the output
152
- 3. **Evaluate** - did it work? What's the current state?
153
- 4. **Decide** - is the task complete or do we need another script?
154
- 5. **Repeat** until task is done
155
-
156
- ### No TypeScript in Browser Context
157
-
158
- Code passed to `page.evaluate()` runs in the browser, which doesn't understand TypeScript:
159
-
160
- ```typescript
161
- // ✅ Correct: plain JavaScript
162
- const text = await page.evaluate(() => {
163
- return document.body.innerText;
164
- });
165
-
166
- // ❌ Wrong: TypeScript syntax will fail at runtime
167
- const text = await page.evaluate(() => {
168
- const el: HTMLElement = document.body; // Type annotation breaks in browser!
169
- return el.innerText;
170
- });
171
- ```
172
-
173
- ## Scraping Data
174
-
175
- For scraping large datasets, intercept and replay network requests rather than scrolling the DOM. See [references/scraping.md](references/scraping.md) for the complete guide covering request capture, schema discovery, and paginated API replay.
176
-
177
- ## Client API
178
-
179
- ```typescript
180
- const client = await connect();
181
-
182
- // Get or create named page (viewport only applies to new pages)
183
- const page = await client.page("name");
184
- const pageWithSize = await client.page("name", { viewport: { width: 1920, height: 1080 } });
185
-
186
- const pages = await client.list(); // List all page names
187
- await client.close("name"); // Close a page
188
- await client.disconnect(); // Disconnect (pages persist while the server runs)
189
-
190
- // ARIA Snapshot methods
191
- const snapshot = await client.getAISnapshot("name"); // Get accessibility tree
192
- const element = await client.selectSnapshotRef("name", "e5"); // Get element by ref
193
- ```
194
-
195
- The `page` object is a standard Playwright Page.
196
-
197
- ## Waiting
198
-
199
- ```javascript
200
- await waitForPageLoad(page); // After navigation
201
- await page.waitForSelector(".results"); // For specific elements
202
- await page.waitForURL("**/success"); // For specific URL
203
- ```
204
-
205
- ## Inspecting Page State
206
-
207
- ### Screenshots
208
-
209
- ```javascript
210
- import { tmpdir } from "node:os";
211
- import { join } from "node:path";
212
-
213
- const screenshotPath = join(tmpdir(), "dev-browser-screenshot.png");
214
- const fullScreenshotPath = join(tmpdir(), "dev-browser-full.png");
215
- await page.screenshot({ path: screenshotPath });
216
- await page.screenshot({ path: fullScreenshotPath, fullPage: true });
217
- ```
218
-
219
- Inspect the files, then remove them no later than task completion.
220
-
221
- ### ARIA Snapshot (Element Discovery)
222
-
223
- Use `getAISnapshot()` to discover page elements. Returns YAML-formatted accessibility tree:
224
-
225
- ```yaml
226
- - banner:
227
- - link "Hacker News" [ref=e1]
228
- - navigation:
229
- - link "new" [ref=e2]
230
- - main:
231
- - list:
232
- - listitem:
233
- - link "Article Title" [ref=e8]
234
- - link "328 comments" [ref=e9]
235
- - contentinfo:
236
- - textbox [ref=e10]
237
- - /placeholder: "Search"
238
- ```
239
-
240
- **Interpreting refs:**
241
-
242
- - `[ref=eN]` - Element reference for interaction (visible, clickable elements only)
243
- - `[checked]`, `[disabled]`, `[expanded]` - Element states
244
- - `[level=N]` - Heading level
245
- - `/url:`, `/placeholder:` - Element properties
246
-
247
- **Interacting with refs:**
248
-
249
- ```typescript
250
- const snapshot = await client.getAISnapshot("hackernews");
251
- console.log(snapshot); // Find the ref you need
252
-
253
- const element = await client.selectSnapshotRef("hackernews", "e2");
254
- await element.click();
255
- ```
256
-
257
- ## Error Recovery
258
-
259
- Page state persists after failures while the server process runs. Reuse the external script pattern above from the OS temporary directory or task workspace:
260
-
261
- ```javascript
262
- const client = await connect();
263
- const page = await client.page("hackernews");
264
-
265
- const debugScreenshotPath = join(tmpdir(), "dev-browser-debug.png");
266
- await page.screenshot({ path: debugScreenshotPath });
267
- console.log({
268
- url: page.url(),
269
- title: await page.title(),
270
- bodyText: await page.textContent("body").then((t) => t?.slice(0, 200)),
271
- debugScreenshotPath,
272
- });
273
-
274
- await client.disconnect();
275
- ```
276
-
277
- Run it with the same cross-platform invocation and delete the debug script and screenshot when finished:
278
-
279
- ```text
280
- node "PATH_TO_DEBUG_SCRIPT.mjs" "PATH_TO_INSTALLED_DEV_BROWSER"
281
- ```
@@ -1 +0,0 @@
1
- export {};
@@ -1,90 +0,0 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { createRequire } from "node:module";
3
- import { join } from "node:path";
4
- import { formatHttpUrl, parseEntrypointArgs, resolveHostForProbe } from "../src/entrypoint.js";
5
- import { assertRuntimeDependenciesAvailable, getInvalidRuntimeDependencies, getLockedRuntimeDependencies, isPlaywrightChromiumInstalled, isTcpPortInUse, resolveSkillDirFromEntrypoint, } from "../src/runtime.js";
6
- import { assertPlaywrightChromiumAvailable, preflightStandaloneStartup, runEntrypoint, } from "../src/startup.js";
7
- const skillDir = resolveSkillDirFromEntrypoint(import.meta.url);
8
- const require = createRequire(import.meta.url);
9
- async function main() {
10
- const args = parseEntrypointArgs(process.argv.slice(2));
11
- await ensureSkillDependencies();
12
- await runEntrypoint(args, {
13
- serveStandalone: async (options) => {
14
- const { serve } = await import("../src/index.js");
15
- return serve(options);
16
- },
17
- serveExtension: async (options) => {
18
- const { serveRelay } = await import("../src/relay.js");
19
- return serveRelay(options);
20
- },
21
- registerShutdown,
22
- keepAlive: () => new Promise(() => { }),
23
- log: (line) => console.log(line),
24
- ensureBrowser: async () => {
25
- const { registry } = require("playwright-core/lib/server/registry/index");
26
- await assertPlaywrightChromiumAvailable({
27
- isInstalled: () => isPlaywrightChromiumInstalled({
28
- headless: args.headless,
29
- findExecutable: (name) => registry.findExecutable(name),
30
- exists: existsSync,
31
- }),
32
- });
33
- },
34
- preflightStandalone: () => preflightStandaloneStartup(args, {
35
- checkServer: async (host, port) => {
36
- try {
37
- const response = await fetch(formatHttpUrl(resolveHostForProbe(host), port), {
38
- signal: AbortSignal.timeout(1000),
39
- });
40
- if (!response.ok) {
41
- return { ok: false };
42
- }
43
- const info = (await response.json());
44
- return { ok: true, info };
45
- }
46
- catch {
47
- return { ok: false };
48
- }
49
- },
50
- isPortInUse: isTcpPortInUse,
51
- log: (line) => console.log(line),
52
- }),
53
- });
54
- }
55
- async function ensureSkillDependencies() {
56
- const packageLock = JSON.parse(readFileSync(join(skillDir, "package-lock.json"), "utf8"));
57
- const invalidDependencies = getInvalidRuntimeDependencies({
58
- skillDir,
59
- lockedDependencies: getLockedRuntimeDependencies(packageLock),
60
- readPackageVersion: (path) => {
61
- try {
62
- const installed = JSON.parse(readFileSync(path, "utf8"));
63
- return typeof installed.version === "string" ? installed.version : undefined;
64
- }
65
- catch {
66
- return undefined;
67
- }
68
- },
69
- });
70
- assertRuntimeDependenciesAvailable({
71
- invalidDependencies,
72
- });
73
- }
74
- function registerShutdown(stop) {
75
- let shutdownPromise;
76
- const shutdown = () => {
77
- shutdownPromise ??= (async () => {
78
- await stop();
79
- process.exit(0);
80
- })();
81
- return shutdownPromise;
82
- };
83
- process.on("SIGINT", shutdown);
84
- process.on("SIGTERM", shutdown);
85
- process.on("SIGHUP", shutdown);
86
- }
87
- main().catch((error) => {
88
- console.error("Failed to start dev-browser:", error);
89
- process.exit(1);
90
- });
@@ -1,92 +0,0 @@
1
- import { type ElementHandle, type Page } from "playwright";
2
- import type { ViewportSize } from "./types.js";
3
- /**
4
- * Options for waiting for page load
5
- */
6
- export interface WaitForPageLoadOptions {
7
- /** Maximum time to wait in ms (default: 10000) */
8
- timeout?: number;
9
- /** How often to check page state in ms (default: 50) */
10
- pollInterval?: number;
11
- /** Minimum time to wait even if page appears ready in ms (default: 100) */
12
- minimumWait?: number;
13
- /** Wait for network to be idle (no pending requests) (default: true) */
14
- waitForNetworkIdle?: boolean;
15
- }
16
- /**
17
- * Result of waiting for page load
18
- */
19
- export interface WaitForPageLoadResult {
20
- /** Whether the page is considered loaded */
21
- success: boolean;
22
- /** Document ready state when finished */
23
- readyState: string;
24
- /** Number of pending network requests when finished */
25
- pendingRequests: number;
26
- /** Time spent waiting in ms */
27
- waitTimeMs: number;
28
- /** Whether timeout was reached */
29
- timedOut: boolean;
30
- }
31
- /**
32
- * Wait for a page to finish loading using document.readyState and Playwright request events.
33
- *
34
- * Uses browser-use's approach of:
35
- * - Checking document.readyState for 'complete'
36
- * - Monitoring pending network requests via Playwright
37
- * - Filtering out ads, tracking, and non-critical resources
38
- * - Graceful timeout handling (continues even if timeout reached)
39
- */
40
- export declare function waitForPageLoad(page: Page, options?: WaitForPageLoadOptions): Promise<WaitForPageLoadResult>;
41
- /** Server mode information */
42
- export interface ServerInfo {
43
- wsEndpoint: string;
44
- mode: "standalone" | "extension";
45
- extensionConnected?: boolean;
46
- }
47
- /**
48
- * Options for creating or getting a page
49
- */
50
- export interface PageOptions {
51
- /** Viewport size for new pages */
52
- viewport?: ViewportSize;
53
- }
54
- export interface DevBrowserClient {
55
- page: (name: string, options?: PageOptions) => Promise<Page>;
56
- list: () => Promise<string[]>;
57
- close: (name: string) => Promise<void>;
58
- disconnect: () => Promise<void>;
59
- /**
60
- * Get AI-friendly ARIA snapshot for a page.
61
- * Returns YAML format with refs like [ref=e1], [ref=e2].
62
- * Refs are stored on window.__devBrowserRefs for cross-connection persistence.
63
- */
64
- getAISnapshot: (name: string) => Promise<string>;
65
- /**
66
- * Get an element handle by its ref from the last getAISnapshot call.
67
- * Refs persist across Playwright connections.
68
- */
69
- selectSnapshotRef: (name: string, ref: string) => Promise<ElementHandle | null>;
70
- /**
71
- * Get server information including mode and extension connection status.
72
- */
73
- getServerInfo: () => Promise<ServerInfo>;
74
- }
75
- interface TargetLookupSession {
76
- send(method: "Target.getTargetInfo"): Promise<{
77
- targetInfo: {
78
- targetId: string;
79
- };
80
- }>;
81
- detach(): Promise<void>;
82
- }
83
- interface TargetLookupContext<TPage> {
84
- pages(): TPage[];
85
- newCDPSession(page: TPage): Promise<TargetLookupSession>;
86
- }
87
- interface TargetLookupBrowser<TPage> {
88
- contexts(): Array<TargetLookupContext<TPage>>;
89
- }
90
- export declare function findPageByTargetId<TPage>(browser: TargetLookupBrowser<TPage>, targetId: string): Promise<TPage | null>;
91
- export declare function connect(serverUrl?: string): Promise<DevBrowserClient>;
92
- export {};