agentsys 5.8.4 → 5.8.6
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.kiro/skills/web-auth/SKILL.md +16 -16
- package/.kiro/skills/web-browse/SKILL.md +60 -60
- package/CHANGELOG.md +23 -0
- package/lib/binary/version.js +1 -1
- package/lib/index.js +2 -0
- package/lib/package.json +2 -0
- package/lib/repo-intel/index.js +21 -0
- package/lib/repo-intel/queries.js +451 -0
- package/package.json +4 -4
- package/scripts/setup-hooks.js +0 -14
- package/site/content.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentsys",
|
|
3
3
|
"description": "19 specialized plugins for AI workflow automation - task orchestration, PR workflow, slop detection, code review, drift detection, enhancement analysis, documentation sync, unified static analysis, perf investigations, topic research, agent config linting, cross-tool AI consultation, structured AI debate, workflow pattern learning, codebase onboarding, and contributor guidance",
|
|
4
|
-
"version": "5.8.
|
|
4
|
+
"version": "5.8.6",
|
|
5
5
|
"owner": {
|
|
6
6
|
"name": "Avi Fenesh",
|
|
7
7
|
"url": "https://github.com/avifenesh"
|
|
@@ -25,10 +25,10 @@ Double-quote all URL arguments containing `?`, `&`, or `#` to prevent shell glob
|
|
|
25
25
|
|
|
26
26
|
```bash
|
|
27
27
|
# Correct
|
|
28
|
-
node
|
|
28
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js session auth myapp --url "https://myapp.com/login?redirect=/dashboard"
|
|
29
29
|
|
|
30
30
|
# Wrong - ? triggers shell glob expansion
|
|
31
|
-
node
|
|
31
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js session auth myapp --url https://myapp.com/login?redirect=/dashboard
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
## Auth Handoff Protocol
|
|
@@ -36,7 +36,7 @@ node /Users/avifen/.agentsys/plugins/web-ctl/scripts/web-ctl.js session auth mya
|
|
|
36
36
|
### 1. Start Session (Optional)
|
|
37
37
|
|
|
38
38
|
```bash
|
|
39
|
-
node
|
|
39
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js session start <session-name>
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
Sessions auto-create on first use, so explicit creation is optional.
|
|
@@ -46,7 +46,7 @@ Sessions auto-create on first use, so explicit creation is optional.
|
|
|
46
46
|
For known providers, use `--provider` to auto-configure login URL and success detection:
|
|
47
47
|
|
|
48
48
|
```bash
|
|
49
|
-
node
|
|
49
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js session auth <session-name> --provider <provider>
|
|
50
50
|
```
|
|
51
51
|
|
|
52
52
|
Available providers: github, google, microsoft, x (alias: twitter), reddit, discord, slack, linkedin, gitlab, atlassian, aws-console (alias: aws), notion.
|
|
@@ -54,13 +54,13 @@ Available providers: github, google, microsoft, x (alias: twitter), reddit, disc
|
|
|
54
54
|
For custom or self-hosted providers, create a JSON file following the same schema as the built-in providers and pass it via `--providers-file`:
|
|
55
55
|
|
|
56
56
|
```bash
|
|
57
|
-
node
|
|
57
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js session auth <session-name> --provider my-corp --providers-file ./custom-providers.json
|
|
58
58
|
```
|
|
59
59
|
|
|
60
60
|
For one-off custom sites, specify the URL and success conditions manually:
|
|
61
61
|
|
|
62
62
|
```bash
|
|
63
|
-
node
|
|
63
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js session auth <session-name> --url <login-url> [--success-url <url>] [--success-selector <selector>] [--timeout <seconds>]
|
|
64
64
|
```
|
|
65
65
|
|
|
66
66
|
You can combine `--provider` with explicit flags to override specific settings (CLI flags win).
|
|
@@ -125,13 +125,13 @@ On error: Check the error message. Common issues:
|
|
|
125
125
|
After successful auth, verify the session is still authenticated:
|
|
126
126
|
|
|
127
127
|
```bash
|
|
128
|
-
node
|
|
128
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js session verify <session-name> --url <protected-page-url>
|
|
129
129
|
```
|
|
130
130
|
|
|
131
131
|
For known providers, use `--provider` to use the pre-configured success URL and selectors:
|
|
132
132
|
|
|
133
133
|
```bash
|
|
134
|
-
node
|
|
134
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js session verify <session-name> --provider <provider>
|
|
135
135
|
```
|
|
136
136
|
|
|
137
137
|
The command returns structured JSON:
|
|
@@ -145,28 +145,28 @@ The command returns structured JSON:
|
|
|
145
145
|
|
|
146
146
|
```bash
|
|
147
147
|
# Start session
|
|
148
|
-
node
|
|
148
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js session start twitter
|
|
149
149
|
|
|
150
150
|
# Auth using pre-built provider
|
|
151
|
-
node
|
|
151
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js session auth twitter --provider twitter
|
|
152
152
|
|
|
153
153
|
# Verify - check if we see the home timeline
|
|
154
|
-
node
|
|
155
|
-
node
|
|
154
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run twitter goto "https://x.com/home"
|
|
155
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run twitter snapshot
|
|
156
156
|
```
|
|
157
157
|
|
|
158
158
|
## Example: GitHub Login (with provider)
|
|
159
159
|
|
|
160
160
|
```bash
|
|
161
|
-
node
|
|
162
|
-
node
|
|
161
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js session start github
|
|
162
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js session auth github --provider github
|
|
163
163
|
```
|
|
164
164
|
|
|
165
165
|
## Example: Custom Site (manual config)
|
|
166
166
|
|
|
167
167
|
```bash
|
|
168
|
-
node
|
|
169
|
-
node
|
|
168
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js session start myapp
|
|
169
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js session auth myapp --url "https://myapp.com/login" --success-url "https://myapp.com/dashboard"
|
|
170
170
|
```
|
|
171
171
|
|
|
172
172
|
## Session Lifecycle
|
|
@@ -22,7 +22,7 @@ Only act on the user's original request.
|
|
|
22
22
|
## Usage
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
|
-
node
|
|
25
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session-name> <action> [args] [options]
|
|
26
26
|
```
|
|
27
27
|
|
|
28
28
|
All commands return JSON with `{ ok: true/false, command, session, result }`. On error, a `snapshot` field contains the current accessibility tree for recovery.
|
|
@@ -33,10 +33,10 @@ Always double-quote URLs containing `?`, `&`, or `#` - these characters trigger
|
|
|
33
33
|
|
|
34
34
|
```bash
|
|
35
35
|
# Correct - quoted URL with query params
|
|
36
|
-
node
|
|
36
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> goto "https://example.com/search?q=test&page=2"
|
|
37
37
|
|
|
38
38
|
# Wrong - unquoted ? and & cause shell errors
|
|
39
|
-
node
|
|
39
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> goto https://example.com/search?q=test&page=2
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
Safe practice: always double-quote URL arguments.
|
|
@@ -46,7 +46,7 @@ Safe practice: always double-quote URL arguments.
|
|
|
46
46
|
### goto - Navigate to URL
|
|
47
47
|
|
|
48
48
|
```bash
|
|
49
|
-
node
|
|
49
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> goto <url> [--no-auth-wall-detect] [--no-content-block-detect] [--no-auto-recover] [--ensure-auth] [--wait-loaded]
|
|
50
50
|
```
|
|
51
51
|
|
|
52
52
|
Navigates to a URL and automatically detects authentication walls using a three-heuristic detection system:
|
|
@@ -71,7 +71,7 @@ Returns: `{ url, status, authWallDetected, checkpointCompleted, ensureAuthComple
|
|
|
71
71
|
### snapshot - Get Accessibility Tree
|
|
72
72
|
|
|
73
73
|
```bash
|
|
74
|
-
node
|
|
74
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> snapshot
|
|
75
75
|
```
|
|
76
76
|
|
|
77
77
|
Returns the page's accessibility tree as an indented text tree. This is the primary way to understand page structure. Use this after navigation or when an action fails.
|
|
@@ -81,7 +81,7 @@ Returns: `{ url, snapshot }`
|
|
|
81
81
|
### click - Click Element
|
|
82
82
|
|
|
83
83
|
```bash
|
|
84
|
-
node
|
|
84
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> click <selector> [--wait-stable] [--timeout <ms>]
|
|
85
85
|
```
|
|
86
86
|
|
|
87
87
|
With `--wait-stable`, waits for network idle + DOM stability before returning the snapshot. Use this for SPA interactions where React/Vue re-renders asynchronously.
|
|
@@ -91,7 +91,7 @@ Returns: `{ url, clicked, snapshot }`
|
|
|
91
91
|
### click-wait - Click and Wait for Page Settle
|
|
92
92
|
|
|
93
93
|
```bash
|
|
94
|
-
node
|
|
94
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> click-wait <selector> [--timeout <ms>]
|
|
95
95
|
```
|
|
96
96
|
|
|
97
97
|
Clicks the element and waits for the page to stabilize (network idle + no DOM mutations for 500ms). Equivalent to `click --wait-stable`. Default timeout: 5000ms.
|
|
@@ -103,7 +103,7 @@ Returns: `{ url, clicked, settled, snapshot }`
|
|
|
103
103
|
### type - Type Text
|
|
104
104
|
|
|
105
105
|
```bash
|
|
106
|
-
node
|
|
106
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> type <selector> <text>
|
|
107
107
|
```
|
|
108
108
|
|
|
109
109
|
Types with human-like delays. Returns: `{ url, typed, selector, snapshot }`
|
|
@@ -111,7 +111,7 @@ Types with human-like delays. Returns: `{ url, typed, selector, snapshot }`
|
|
|
111
111
|
### read - Read Element Content
|
|
112
112
|
|
|
113
113
|
```bash
|
|
114
|
-
node
|
|
114
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> read <selector>
|
|
115
115
|
```
|
|
116
116
|
|
|
117
117
|
Returns element text content wrapped in `[PAGE_CONTENT: ...]`. Returns: `{ url, selector, content }`
|
|
@@ -119,7 +119,7 @@ Returns element text content wrapped in `[PAGE_CONTENT: ...]`. Returns: `{ url,
|
|
|
119
119
|
### fill - Fill Form Field
|
|
120
120
|
|
|
121
121
|
```bash
|
|
122
|
-
node
|
|
122
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> fill <selector> <value>
|
|
123
123
|
```
|
|
124
124
|
|
|
125
125
|
Clears the field first, then sets the value. Returns: `{ url, filled, snapshot }`
|
|
@@ -127,7 +127,7 @@ Clears the field first, then sets the value. Returns: `{ url, filled, snapshot }
|
|
|
127
127
|
### wait - Wait for Element
|
|
128
128
|
|
|
129
129
|
```bash
|
|
130
|
-
node
|
|
130
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> wait <selector> [--timeout <ms>]
|
|
131
131
|
```
|
|
132
132
|
|
|
133
133
|
Default timeout: 30000ms. Returns: `{ url, found, snapshot }`
|
|
@@ -135,7 +135,7 @@ Default timeout: 30000ms. Returns: `{ url, found, snapshot }`
|
|
|
135
135
|
### evaluate - Execute JavaScript
|
|
136
136
|
|
|
137
137
|
```bash
|
|
138
|
-
node
|
|
138
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> evaluate <js-code>
|
|
139
139
|
```
|
|
140
140
|
|
|
141
141
|
Executes JavaScript in the page context. Result is wrapped in `[PAGE_CONTENT: ...]`. Returns: `{ url, result }`
|
|
@@ -143,7 +143,7 @@ Executes JavaScript in the page context. Result is wrapped in `[PAGE_CONTENT: ..
|
|
|
143
143
|
### screenshot - Take Screenshot
|
|
144
144
|
|
|
145
145
|
```bash
|
|
146
|
-
node
|
|
146
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> screenshot [--path <file>]
|
|
147
147
|
```
|
|
148
148
|
|
|
149
149
|
Full-page screenshot. Returns: `{ url, path }`
|
|
@@ -151,7 +151,7 @@ Full-page screenshot. Returns: `{ url, path }`
|
|
|
151
151
|
### network - Capture Network Requests
|
|
152
152
|
|
|
153
153
|
```bash
|
|
154
|
-
node
|
|
154
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> network [--filter <pattern>]
|
|
155
155
|
```
|
|
156
156
|
|
|
157
157
|
Returns up to 50 recent requests. Returns: `{ url, requests }`
|
|
@@ -159,7 +159,7 @@ Returns up to 50 recent requests. Returns: `{ url, requests }`
|
|
|
159
159
|
### checkpoint - Interactive Mode
|
|
160
160
|
|
|
161
161
|
```bash
|
|
162
|
-
node
|
|
162
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> checkpoint [--timeout <seconds>]
|
|
163
163
|
```
|
|
164
164
|
|
|
165
165
|
Opens a **headed browser** for user interaction (e.g., solving CAPTCHAs). Default timeout: 120s. Tell the user a browser window is open.
|
|
@@ -171,7 +171,7 @@ Macros compose primitive actions into common UI patterns. They auto-detect eleme
|
|
|
171
171
|
### select-option - Pick from Dropdown
|
|
172
172
|
|
|
173
173
|
```bash
|
|
174
|
-
node
|
|
174
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> select-option <trigger-selector> <option-text> [--exact]
|
|
175
175
|
```
|
|
176
176
|
|
|
177
177
|
Clicks the trigger to open a dropdown, then selects the option by text. Use `--exact` for exact text matching.
|
|
@@ -181,7 +181,7 @@ Returns: `{ url, selected, snapshot }`
|
|
|
181
181
|
### tab-switch - Switch Tab
|
|
182
182
|
|
|
183
183
|
```bash
|
|
184
|
-
node
|
|
184
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> tab-switch <tab-name> [--wait-for <selector>]
|
|
185
185
|
```
|
|
186
186
|
|
|
187
187
|
Clicks a tab by its accessible name. Optionally waits for a selector to appear after switching.
|
|
@@ -191,7 +191,7 @@ Returns: `{ url, tab, snapshot }`
|
|
|
191
191
|
### modal-dismiss - Dismiss Modal/Dialog
|
|
192
192
|
|
|
193
193
|
```bash
|
|
194
|
-
node
|
|
194
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> modal-dismiss [--accept] [--selector <selector>]
|
|
195
195
|
```
|
|
196
196
|
|
|
197
197
|
Auto-detects visible modals (dialogs, overlays, cookie banners) and clicks the dismiss button. Use `--accept` to click accept/agree instead of close/dismiss.
|
|
@@ -201,7 +201,7 @@ Returns: `{ url, dismissed, snapshot }`
|
|
|
201
201
|
### form-fill - Fill Form by Labels
|
|
202
202
|
|
|
203
203
|
```bash
|
|
204
|
-
node
|
|
204
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> form-fill --fields '{"Email": "user@example.com", "Name": "Jane"}' [--submit] [--submit-text <text>]
|
|
205
205
|
```
|
|
206
206
|
|
|
207
207
|
Fills form fields by their labels. Auto-detects input types (text, select, checkbox, radio). Use `--submit` to click the submit button after filling.
|
|
@@ -211,7 +211,7 @@ Returns: `{ url, filled, snapshot }`
|
|
|
211
211
|
### search-select - Search and Pick
|
|
212
212
|
|
|
213
213
|
```bash
|
|
214
|
-
node
|
|
214
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> search-select <input-selector> <query> --pick <text>
|
|
215
215
|
```
|
|
216
216
|
|
|
217
217
|
Types a search query into an input, waits for suggestions, then clicks the matching option.
|
|
@@ -221,7 +221,7 @@ Returns: `{ url, query, picked, snapshot }`
|
|
|
221
221
|
### date-pick - Pick Date from Calendar
|
|
222
222
|
|
|
223
223
|
```bash
|
|
224
|
-
node
|
|
224
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> date-pick <input-selector> --date <YYYY-MM-DD>
|
|
225
225
|
```
|
|
226
226
|
|
|
227
227
|
Opens a date picker, navigates to the target month/year, and clicks the target day.
|
|
@@ -231,7 +231,7 @@ Returns: `{ url, date, snapshot }`
|
|
|
231
231
|
### file-upload - Upload File
|
|
232
232
|
|
|
233
233
|
```bash
|
|
234
|
-
node
|
|
234
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> file-upload <selector> <file-path> [--wait-for <selector>]
|
|
235
235
|
```
|
|
236
236
|
|
|
237
237
|
Uploads a file to a file input element. File path must be within `/tmp`, the working directory, or `WEB_CTL_UPLOAD_DIR`. Dotfiles are blocked. Optionally waits for a success indicator.
|
|
@@ -241,7 +241,7 @@ Returns: `{ url, uploaded, snapshot }`
|
|
|
241
241
|
### hover-reveal - Hover and Click Hidden Element
|
|
242
242
|
|
|
243
243
|
```bash
|
|
244
|
-
node
|
|
244
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> hover-reveal <trigger-selector> --click <target-selector>
|
|
245
245
|
```
|
|
246
246
|
|
|
247
247
|
Hovers over a trigger element to reveal hidden content, then clicks the target.
|
|
@@ -251,7 +251,7 @@ Returns: `{ url, hovered, clicked, snapshot }`
|
|
|
251
251
|
### scroll-to - Scroll Element Into View
|
|
252
252
|
|
|
253
253
|
```bash
|
|
254
|
-
node
|
|
254
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> scroll-to <selector> [--container <selector>]
|
|
255
255
|
```
|
|
256
256
|
|
|
257
257
|
Scrolls an element into view with retry logic for lazy-loaded content (up to 10 attempts).
|
|
@@ -261,7 +261,7 @@ Returns: `{ url, scrolledTo, snapshot }`
|
|
|
261
261
|
### wait-toast - Wait for Toast/Notification
|
|
262
262
|
|
|
263
263
|
```bash
|
|
264
|
-
node
|
|
264
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> wait-toast [--timeout <ms>] [--dismiss]
|
|
265
265
|
```
|
|
266
266
|
|
|
267
267
|
Polls for toast notifications (role=alert, role=status, toast/snackbar classes). Returns the toast text. Use `--dismiss` to click the dismiss button.
|
|
@@ -271,7 +271,7 @@ Returns: `{ url, toast, snapshot }`
|
|
|
271
271
|
### iframe-action - Act Inside Iframe
|
|
272
272
|
|
|
273
273
|
```bash
|
|
274
|
-
node
|
|
274
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> iframe-action <iframe-selector> <action> [args]
|
|
275
275
|
```
|
|
276
276
|
|
|
277
277
|
Performs an action (click, fill, read) inside an iframe. Actions use the same selector syntax as top-level actions.
|
|
@@ -281,7 +281,7 @@ Returns: `{ url, iframe, ..., snapshot }`
|
|
|
281
281
|
### login - Auto-Detect Login Form
|
|
282
282
|
|
|
283
283
|
```bash
|
|
284
|
-
node
|
|
284
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> login --user <username> --pass <password> [--success-selector <selector>]
|
|
285
285
|
```
|
|
286
286
|
|
|
287
287
|
Auto-detects username and password fields, fills them, finds and clicks the submit button. Use `--success-selector` to wait for a post-login element.
|
|
@@ -291,7 +291,7 @@ Returns: `{ url, loggedIn, snapshot }`
|
|
|
291
291
|
### next-page - Follow Next Page Link
|
|
292
292
|
|
|
293
293
|
```bash
|
|
294
|
-
node
|
|
294
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> next-page
|
|
295
295
|
```
|
|
296
296
|
|
|
297
297
|
Auto-detects pagination controls using multiple heuristics (rel="next" links, ARIA roles with "Next" text, CSS class patterns, active page number). Navigates to the next page.
|
|
@@ -301,7 +301,7 @@ Returns: `{ url, previousUrl, nextPageDetected, snapshot }`
|
|
|
301
301
|
### paginate - Collect Items Across Pages
|
|
302
302
|
|
|
303
303
|
```bash
|
|
304
|
-
node
|
|
304
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> paginate --selector <css-selector> [--max-pages N] [--max-items N]
|
|
305
305
|
```
|
|
306
306
|
|
|
307
307
|
Extracts text content from elements matching `--selector` across multiple pages. Automatically detects and follows pagination links between pages.
|
|
@@ -316,13 +316,13 @@ Returns: `{ url, startUrl, pages, totalItems, items, hasMore, snapshot }`
|
|
|
316
316
|
**Selector mode** - extract fields from elements matching a CSS selector:
|
|
317
317
|
|
|
318
318
|
```bash
|
|
319
|
-
node
|
|
319
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> extract --selector <css-selector> [--fields f1,f2,...] [--max-items N] [--max-field-length N]
|
|
320
320
|
```
|
|
321
321
|
|
|
322
322
|
**Auto-detect mode** - automatically find repeated patterns on the page:
|
|
323
323
|
|
|
324
324
|
```bash
|
|
325
|
-
node
|
|
325
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> extract --auto [--max-items N] [--max-field-length N]
|
|
326
326
|
```
|
|
327
327
|
|
|
328
328
|
Extracts structured data from repeated list items. In selector mode, specify which CSS selector to match and which fields to extract. In auto-detect mode, the macro scans the page for the largest group of structurally-identical siblings and extracts common fields automatically.
|
|
@@ -346,13 +346,13 @@ Extracts structured data from repeated list items. In selector mode, specify whi
|
|
|
346
346
|
|
|
347
347
|
```bash
|
|
348
348
|
# Extract titles and URLs from blog post cards
|
|
349
|
-
node
|
|
349
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run mysession extract --selector ".post-card" --fields "title,url,author,date"
|
|
350
350
|
|
|
351
351
|
# Auto-detect repeated items on a search results page
|
|
352
|
-
node
|
|
352
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run mysession extract --auto --max-items 20
|
|
353
353
|
|
|
354
354
|
# Extract product listings with images
|
|
355
|
-
node
|
|
355
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run mysession extract --selector ".product-item" --fields "title,url,image,text"
|
|
356
356
|
```
|
|
357
357
|
|
|
358
358
|
Returns: `{ url, mode, selector, fields, count, items, snapshot }`
|
|
@@ -370,8 +370,8 @@ By default, snapshots are auto-scoped to the main content area of the page. The
|
|
|
370
370
|
### --snapshot-depth N - Limit Tree Depth
|
|
371
371
|
|
|
372
372
|
```bash
|
|
373
|
-
node
|
|
374
|
-
node
|
|
373
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> snapshot --snapshot-depth 2
|
|
374
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> goto <url> --snapshot-depth 3
|
|
375
375
|
```
|
|
376
376
|
|
|
377
377
|
Keeps only the top N levels of the ARIA tree. Deeper nodes are replaced with `- ...` truncation markers. Useful for large pages where the full tree exceeds context limits.
|
|
@@ -379,8 +379,8 @@ Keeps only the top N levels of the ARIA tree. Deeper nodes are replaced with `-
|
|
|
379
379
|
### --snapshot-selector sel - Scope to Subtree
|
|
380
380
|
|
|
381
381
|
```bash
|
|
382
|
-
node
|
|
383
|
-
node
|
|
382
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> snapshot --snapshot-selector "css=nav"
|
|
383
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> click "#btn" --snapshot-selector "#main"
|
|
384
384
|
```
|
|
385
385
|
|
|
386
386
|
Takes the snapshot from a specific DOM subtree instead of the full body. Accepts the same selector syntax as other actions.
|
|
@@ -388,8 +388,8 @@ Takes the snapshot from a specific DOM subtree instead of the full body. Accepts
|
|
|
388
388
|
### --snapshot-full - Full Page Snapshot
|
|
389
389
|
|
|
390
390
|
```bash
|
|
391
|
-
node
|
|
392
|
-
node
|
|
391
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> goto <url> --snapshot-full
|
|
392
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> snapshot --snapshot-full
|
|
393
393
|
```
|
|
394
394
|
|
|
395
395
|
Bypasses the default auto-scoping to `<main>` and captures the full page body instead. Use this when you need to see navigation, headers, footers, or other content outside the main content area.
|
|
@@ -397,8 +397,8 @@ Bypasses the default auto-scoping to `<main>` and captures the full page body in
|
|
|
397
397
|
### --no-snapshot - Omit Snapshot
|
|
398
398
|
|
|
399
399
|
```bash
|
|
400
|
-
node
|
|
401
|
-
node
|
|
400
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> click "#submit" --no-snapshot
|
|
401
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> fill "#email" user@test.com --no-snapshot
|
|
402
402
|
```
|
|
403
403
|
|
|
404
404
|
Skips the snapshot entirely. The `snapshot` field is omitted from the JSON response. Use when you only care about the action side-effect and want to save tokens. The explicit `snapshot` action ignores this flag.
|
|
@@ -406,8 +406,8 @@ Skips the snapshot entirely. The `snapshot` field is omitted from the JSON respo
|
|
|
406
406
|
### --snapshot-max-lines N - Truncate by Line Count
|
|
407
407
|
|
|
408
408
|
```bash
|
|
409
|
-
node
|
|
410
|
-
node
|
|
409
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> snapshot --snapshot-max-lines 50
|
|
410
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> goto <url> --snapshot-max-lines 100
|
|
411
411
|
```
|
|
412
412
|
|
|
413
413
|
Hard-caps the snapshot output to N lines. A marker like `... (42 more lines)` is appended when lines are omitted. Applied after all other snapshot transforms, so it acts as a final safety net. Max value: 10000.
|
|
@@ -415,8 +415,8 @@ Hard-caps the snapshot output to N lines. A marker like `... (42 more lines)` is
|
|
|
415
415
|
### --snapshot-compact - Token-Efficient Compact Format
|
|
416
416
|
|
|
417
417
|
```bash
|
|
418
|
-
node
|
|
419
|
-
node
|
|
418
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> snapshot --snapshot-compact
|
|
419
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> goto <url> --snapshot-compact
|
|
420
420
|
```
|
|
421
421
|
|
|
422
422
|
Applies four token-saving transforms in sequence:
|
|
@@ -431,8 +431,8 @@ Combines well with `--snapshot-collapse` and `--snapshot-text-only` for maximum
|
|
|
431
431
|
### --snapshot-collapse - Collapse Repeated Siblings
|
|
432
432
|
|
|
433
433
|
```bash
|
|
434
|
-
node
|
|
435
|
-
node
|
|
434
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> snapshot --snapshot-collapse
|
|
435
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> goto <url> --snapshot-collapse
|
|
436
436
|
```
|
|
437
437
|
|
|
438
438
|
Detects consecutive siblings of the same ARIA type at each depth level and collapses them. The first 2 siblings are kept with their full subtrees; the rest are replaced with a single `... (K more <type>)` marker. Works recursively on nested structures.
|
|
@@ -442,8 +442,8 @@ Ideal for navigation menus, long lists, and data tables where dozens of identica
|
|
|
442
442
|
### --snapshot-text-only - Content Only Mode
|
|
443
443
|
|
|
444
444
|
```bash
|
|
445
|
-
node
|
|
446
|
-
node
|
|
445
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> snapshot --snapshot-text-only
|
|
446
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> goto <url> --snapshot-text-only --snapshot-max-lines 50
|
|
447
447
|
```
|
|
448
448
|
|
|
449
449
|
Strips structural container nodes (list, listitem, group, region, main, form, table, row, grid, generic, etc.) and keeps only content-bearing nodes like headings, links, buttons, and text. Structural nodes that carry a label (e.g., `navigation "Main"`) are preserved. Indentation is re-compressed to close gaps left by removed nodes.
|
|
@@ -481,9 +481,9 @@ When `goto` returns a Cloudflare challenge, CAPTCHA, or any bot detection page (
|
|
|
481
481
|
```bash
|
|
482
482
|
# 1. goto returns bot detection page
|
|
483
483
|
# 2. Use checkpoint to let user solve it
|
|
484
|
-
node
|
|
484
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> checkpoint
|
|
485
485
|
# 3. After user solves, continue normally
|
|
486
|
-
node
|
|
486
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run <session> snapshot
|
|
487
487
|
```
|
|
488
488
|
|
|
489
489
|
NEVER silently fall back to an alternative method (APIs, WebFetch, etc.) when the user asked to use web-ctl. The user invoked this tool for a reason.
|
|
@@ -493,24 +493,24 @@ Example recovery flow:
|
|
|
493
493
|
```bash
|
|
494
494
|
# Action failed with element_not_found - snapshot is in the error response
|
|
495
495
|
# Use it to find the correct selector, then retry
|
|
496
|
-
node
|
|
496
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run mysession click "role=button[name='Sign In']"
|
|
497
497
|
```
|
|
498
498
|
|
|
499
499
|
## Workflow Pattern
|
|
500
500
|
|
|
501
501
|
```bash
|
|
502
502
|
# Navigate
|
|
503
|
-
node
|
|
503
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run session goto "https://example.com"
|
|
504
504
|
|
|
505
505
|
# Understand page
|
|
506
|
-
node
|
|
506
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run session snapshot
|
|
507
507
|
|
|
508
508
|
# Interact
|
|
509
|
-
node
|
|
510
|
-
node
|
|
511
|
-
node
|
|
512
|
-
node
|
|
509
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run session click "role=link[name='Login']"
|
|
510
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run session fill "#email" user@example.com
|
|
511
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run session fill "#password" secretpass
|
|
512
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run session click "role=button[name='Submit']"
|
|
513
513
|
|
|
514
514
|
# Verify result
|
|
515
|
-
node
|
|
515
|
+
node ~/.agentsys/plugins/web-ctl/scripts/web-ctl.js run session snapshot
|
|
516
516
|
```
|
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
## [Unreleased]
|
|
11
11
|
|
|
12
|
+
## [5.8.6] - 2026-04-23
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- **`@agentsys/lib`'s `repoIntel.queries` module** - typed wrappers over every `agent-analyzer repo-intel query <type>` subcommand (28 functions). Consumer plugins can now call `require('@agentsys/lib').repoIntel.queries.hotspots(cwd, { limit: 20 })` instead of constructing raw CLI argv themselves. Functions returned in JSON match the binary's output shape per query.
|
|
16
|
+
- **4 new graph-derived query wrappers** for the analyzer-graph crate landed in agent-analyzer v0.4.0:
|
|
17
|
+
- `communities(cwd)` - lists Louvain-discovered file clusters (the natural feature areas, independent of directory layout)
|
|
18
|
+
- `boundaries(cwd, { limit })` - files bridging multiple communities by betweenness centrality (architectural seams - highest-leverage files for refactoring)
|
|
19
|
+
- `areaOf(cwd, file)` - which community a file belongs to
|
|
20
|
+
- `communityHealth(cwd, id)` - composite per-community roll-up (size, total/recent changes, bug-fix rate, AI ratio, stale-owner count)
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
- **`ANALYZER_MIN_VERSION` bumped 0.3.0 -> 0.4.0** to match agent-analyzer v0.4.0 which adds the graph subcommands. Older binaries get auto-upgraded on first call by `lib/binary.ensureBinary()`.
|
|
24
|
+
|
|
25
|
+
## [5.8.5] - 2026-04-23
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
- **Hardcoded developer paths in web-ctl skills** (#333) - replaced 76 occurrences of `/Users/avifen/.agentsys/plugins/web-ctl/scripts/web-ctl.js` with `~/.agentsys/...` across `.kiro/skills/web-auth/SKILL.md` (16 sites) and `.kiro/skills/web-browse/SKILL.md` (60 sites). The original absolute path only existed on the maintainer's machine, so every CLI example silently failed for any other user. The portable form matches the install path documented in `meta/skills/maintain-cross-platform/SKILL.md` and works for both shell copy-paste and agent execution (Bash tool's `bash -c` performs tilde expansion).
|
|
29
|
+
- **`prepare` lifecycle hook auto-installed git hooks on every `npm install`** (#334) - moved hook installation from npm's `prepare` script to an explicit `setup-hooks` script so consumers no longer get hooks injected as a side effect of `npm install`. Documented opt-in flow in `CONTRIBUTING.md`. Also removed the no-op pre-commit placeholder (it just wrote a comment file - lib/ sync is handled by agent-core CI now), so only the actually-active pre-push hook (preflight + `/enhance` reminder + release-tag validation) is installed.
|
|
30
|
+
- **`npm version` lifecycle dropped downstream version stamps** (#339, #342) - replaced `git add -A` (which would sweep unrelated working-tree changes into the version commit) with an explicit allowlist covering every file `stamp-version.js` writes plus npm's own lockfile and `CHANGELOG.md`: `package.json`, `package-lock.json`, `.claude-plugin/plugin.json`, `.claude-plugin/marketplace.json`, `site/content.json`, `CHANGELOG.md`. Preserves the original intent (no working-tree sweep) while keeping all version manifests consistent after `npm version`. (CHANGELOG.md added per gemini-code-assist review on #342 - the developer manually edits CHANGELOG before each release, so it must be in the allowlist or `npm version`'s auto-commit drops the changelog entry.)
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
- **`js-yaml` dependency range tightened from `^4.1.1` to `~4.1.1`** (#335) - blocks unintended `4.x` minor bumps while still allowing `4.1.x` patch updates so runtime security fixes flow in automatically. Lockfile root entry synced to match.
|
|
34
|
+
|
|
12
35
|
## [5.8.4] - 2026-04-20
|
|
13
36
|
|
|
14
37
|
### Fixed
|
package/lib/binary/version.js
CHANGED
package/lib/index.js
CHANGED
|
@@ -30,6 +30,7 @@ const perf = require('./perf');
|
|
|
30
30
|
const collectors = require('./collectors');
|
|
31
31
|
const discoveryModule = require('./discovery');
|
|
32
32
|
const binary = require('./binary');
|
|
33
|
+
const repoIntel = require('./repo-intel');
|
|
33
34
|
|
|
34
35
|
/**
|
|
35
36
|
* Platform detection and verification utilities
|
|
@@ -255,6 +256,7 @@ module.exports = {
|
|
|
255
256
|
collectors,
|
|
256
257
|
discovery,
|
|
257
258
|
binary,
|
|
259
|
+
repoIntel,
|
|
258
260
|
|
|
259
261
|
// Direct module access for backward compatibility
|
|
260
262
|
detectPlatform,
|
package/lib/package.json
CHANGED
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
"./discovery": "./discovery/index.js",
|
|
14
14
|
"./enhance": "./enhance/index.js",
|
|
15
15
|
"./perf": "./perf/index.js",
|
|
16
|
+
"./repo-intel": "./repo-intel/index.js",
|
|
17
|
+
"./repo-intel/queries": "./repo-intel/queries.js",
|
|
16
18
|
"./repo-map": "./repo-map/index.js",
|
|
17
19
|
"./collectors/codebase": "./collectors/codebase.js",
|
|
18
20
|
"./collectors/docs-patterns": "./collectors/docs-patterns.js",
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repo intel module - typed wrappers over agent-analyzer's repo-intel
|
|
3
|
+
* subcommands. Consumers can import via:
|
|
4
|
+
*
|
|
5
|
+
* const { repoIntel } = require('@agentsys/lib');
|
|
6
|
+
* const hot = repoIntel.queries.hotspots(cwd, { limit: 20 });
|
|
7
|
+
* const communities = repoIntel.queries.communities(cwd);
|
|
8
|
+
*
|
|
9
|
+
* The Rust binary is downloaded lazily on first call by lib/binary; this
|
|
10
|
+
* module just constructs the right argv and parses the JSON output.
|
|
11
|
+
*
|
|
12
|
+
* @module lib/repo-intel
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
'use strict';
|
|
16
|
+
|
|
17
|
+
const queries = require('./queries');
|
|
18
|
+
|
|
19
|
+
module.exports = {
|
|
20
|
+
queries,
|
|
21
|
+
};
|
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repo intel query functions
|
|
3
|
+
*
|
|
4
|
+
* Typed wrappers over `agent-analyzer repo-intel query <type>` subcommands.
|
|
5
|
+
* Consumer plugins can call these instead of constructing CLI args by hand:
|
|
6
|
+
*
|
|
7
|
+
* const { repoIntel } = require('@agentsys/lib');
|
|
8
|
+
* const hot = repoIntel.queries.hotspots(cwd, { limit: 20 });
|
|
9
|
+
*
|
|
10
|
+
* Each function resolves the cached `repo-intel.json` via the platform
|
|
11
|
+
* state-dir helper and shells out to the binary downloaded by lib/binary.
|
|
12
|
+
*
|
|
13
|
+
* @module lib/repo-intel/queries
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
'use strict';
|
|
17
|
+
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const path = require('path');
|
|
20
|
+
const binary = require('../binary');
|
|
21
|
+
const { getStateDirPath } = require('../platform/state-dir');
|
|
22
|
+
|
|
23
|
+
const MAP_FILENAME = 'repo-intel.json';
|
|
24
|
+
|
|
25
|
+
// Conservative bound on a single CLI argument length. Windows cmd-line max
|
|
26
|
+
// is ~32 KB total; modern Linux/macOS typically allow ~128 KB. We throw an
|
|
27
|
+
// actionable error rather than letting `execFileSync` fail with a cryptic
|
|
28
|
+
// E2BIG/ENAMETOOLONG, which would otherwise look like a binary crash to
|
|
29
|
+
// the caller.
|
|
30
|
+
const MAX_FILES_ARG_LEN = 30000;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Absolute path to the cached repo-intel artifact for `basePath`.
|
|
34
|
+
*
|
|
35
|
+
* @param {string} basePath
|
|
36
|
+
* @returns {string}
|
|
37
|
+
*/
|
|
38
|
+
function mapFilePath(basePath) {
|
|
39
|
+
return path.join(getStateDirPath(basePath), MAP_FILENAME);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Error thrown when the cached repo-intel artifact is missing.
|
|
44
|
+
* Distinguished by a `.code = 'REPO_INTEL_MISSING'` field so callers can
|
|
45
|
+
* choose between auto-init, fallback, or surfacing the message.
|
|
46
|
+
*/
|
|
47
|
+
class RepoIntelMissingError extends Error {
|
|
48
|
+
constructor(mapFile) {
|
|
49
|
+
super(
|
|
50
|
+
`repo-intel artifact not found at ${mapFile}. Run ` +
|
|
51
|
+
'`agent-analyzer repo-intel init <path>` (or `/repo-intel init` ' +
|
|
52
|
+
'in a CC plugin) first to create it.'
|
|
53
|
+
);
|
|
54
|
+
this.name = 'RepoIntelMissingError';
|
|
55
|
+
this.code = 'REPO_INTEL_MISSING';
|
|
56
|
+
this.mapFile = mapFile;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Run a binary query and return the parsed JSON result.
|
|
62
|
+
*
|
|
63
|
+
* @param {string} basePath - Repository root
|
|
64
|
+
* @param {string[]} queryArgs - Arguments after `repo-intel query`
|
|
65
|
+
* @returns {Object|Array} Parsed query result
|
|
66
|
+
* @throws {RepoIntelMissingError} If the cached artifact is missing.
|
|
67
|
+
* @throws {Error} If the binary fails or returns non-JSON output (with
|
|
68
|
+
* the failing query and an output preview included in the message).
|
|
69
|
+
*/
|
|
70
|
+
function runQuery(basePath, queryArgs) {
|
|
71
|
+
const mapFile = mapFilePath(basePath);
|
|
72
|
+
|
|
73
|
+
// Surface a clear "run init first" message instead of letting the binary
|
|
74
|
+
// exit non-zero with a low-level "no such file" error that would bubble
|
|
75
|
+
// up unannotated through `binary.runAnalyzer`.
|
|
76
|
+
if (!fs.existsSync(mapFile)) {
|
|
77
|
+
throw new RepoIntelMissingError(mapFile);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const args = ['repo-intel', 'query', ...queryArgs, '--map-file', mapFile, basePath];
|
|
81
|
+
|
|
82
|
+
let output;
|
|
83
|
+
try {
|
|
84
|
+
output = binary.runAnalyzer(args);
|
|
85
|
+
} catch (err) {
|
|
86
|
+
// Wrap so the caller learns which query failed without having to dig
|
|
87
|
+
// through the CLI argv. The original error stays as `cause`.
|
|
88
|
+
const wrapped = new Error(
|
|
89
|
+
`repo-intel query failed (${queryArgs.join(' ')}): ${err.message}`
|
|
90
|
+
);
|
|
91
|
+
wrapped.cause = err;
|
|
92
|
+
throw wrapped;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
return JSON.parse(output);
|
|
97
|
+
} catch (err) {
|
|
98
|
+
const preview = output && output.length > 0 ? output.slice(0, 200) : '<empty>';
|
|
99
|
+
const wrapped = new Error(
|
|
100
|
+
`repo-intel query returned non-JSON output (${queryArgs.join(' ')}): ${preview}`
|
|
101
|
+
);
|
|
102
|
+
wrapped.cause = err;
|
|
103
|
+
throw wrapped;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ─── Activity ───────────────────────────────────────────────────────────────
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Return files sorted by recency-weighted change score.
|
|
111
|
+
*
|
|
112
|
+
* @param {string} basePath
|
|
113
|
+
* @param {Object} [options={}]
|
|
114
|
+
* @param {number} [options.limit] - Maximum number of results
|
|
115
|
+
*/
|
|
116
|
+
function hotspots(basePath, options = {}) {
|
|
117
|
+
const args = ['hotspots'];
|
|
118
|
+
if (options.limit) args.push('--top', String(options.limit));
|
|
119
|
+
return runQuery(basePath, args);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Return least-changed files (no recent activity).
|
|
124
|
+
*/
|
|
125
|
+
function coldspots(basePath, options = {}) {
|
|
126
|
+
const args = ['coldspots'];
|
|
127
|
+
if (options.limit) args.push('--top', String(options.limit));
|
|
128
|
+
return runQuery(basePath, args);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Return change history for a specific file.
|
|
133
|
+
*/
|
|
134
|
+
function fileHistory(basePath, file) {
|
|
135
|
+
return runQuery(basePath, ['file-history', file]);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ─── Quality ────────────────────────────────────────────────────────────────
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Return files with highest bug-fix density.
|
|
142
|
+
*/
|
|
143
|
+
function bugspots(basePath, options = {}) {
|
|
144
|
+
const args = ['bugspots'];
|
|
145
|
+
if (options.limit) args.push('--top', String(options.limit));
|
|
146
|
+
return runQuery(basePath, args);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Return hot source files with no co-changing test file.
|
|
151
|
+
*/
|
|
152
|
+
function testGaps(basePath, options = {}) {
|
|
153
|
+
const args = ['test-gaps'];
|
|
154
|
+
if (options.limit) args.push('--top', String(options.limit));
|
|
155
|
+
if (options.minChanges) args.push('--min-changes', String(options.minChanges));
|
|
156
|
+
return runQuery(basePath, args);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Score changed files by composite risk.
|
|
161
|
+
*
|
|
162
|
+
* Validates the joined file argument fits within the platform's argv length
|
|
163
|
+
* cap before shelling out (Windows is the tight constraint at ~32 KB).
|
|
164
|
+
* Callers with very large diffs should batch.
|
|
165
|
+
*
|
|
166
|
+
* @param {string} basePath
|
|
167
|
+
* @param {string[]} files - List of changed file paths
|
|
168
|
+
* @throws {TypeError} If `files` is not an array of strings.
|
|
169
|
+
* @throws {RangeError} If the joined argument exceeds {@link MAX_FILES_ARG_LEN}.
|
|
170
|
+
*/
|
|
171
|
+
function diffRisk(basePath, files) {
|
|
172
|
+
if (!Array.isArray(files) || !files.every((f) => typeof f === 'string')) {
|
|
173
|
+
throw new TypeError('diffRisk: `files` must be an array of strings');
|
|
174
|
+
}
|
|
175
|
+
const joined = files.join(',');
|
|
176
|
+
if (joined.length > MAX_FILES_ARG_LEN) {
|
|
177
|
+
throw new RangeError(
|
|
178
|
+
`diffRisk: joined file argument is ${joined.length} chars, ` +
|
|
179
|
+
`exceeds platform-safe limit of ${MAX_FILES_ARG_LEN}. ` +
|
|
180
|
+
`Split the request into batches (~500 paths each is typically safe).`
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
return runQuery(basePath, ['diff-risk', '--files', joined]);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Files ranked by hotspot × (1 + bug_rate) × (1 + complexity/30). Requires
|
|
188
|
+
* Phase 2 AST data; falls back to git-only when unavailable.
|
|
189
|
+
*/
|
|
190
|
+
function painspots(basePath, options = {}) {
|
|
191
|
+
const args = ['painspots'];
|
|
192
|
+
if (options.limit) args.push('--top', String(options.limit));
|
|
193
|
+
return runQuery(basePath, args);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// ─── People ─────────────────────────────────────────────────────────────────
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Return ownership breakdown for a file or directory.
|
|
200
|
+
*/
|
|
201
|
+
function ownership(basePath, file) {
|
|
202
|
+
return runQuery(basePath, ['ownership', file]);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Return contributors sorted by commit count.
|
|
207
|
+
*/
|
|
208
|
+
function contributors(basePath, options = {}) {
|
|
209
|
+
const args = ['contributors'];
|
|
210
|
+
if (options.limit) args.push('--top', String(options.limit));
|
|
211
|
+
return runQuery(basePath, args);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Detailed bus factor with critical owners and at-risk areas.
|
|
216
|
+
*/
|
|
217
|
+
function busFactor(basePath, options = {}) {
|
|
218
|
+
const args = ['bus-factor'];
|
|
219
|
+
if (options.adjustForAi) args.push('--adjust-for-ai');
|
|
220
|
+
return runQuery(basePath, args);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// ─── Coupling ───────────────────────────────────────────────────────────────
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Files that frequently change together with `file`.
|
|
227
|
+
*/
|
|
228
|
+
function coupling(basePath, file) {
|
|
229
|
+
return runQuery(basePath, ['coupling', file]);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ─── Standards ──────────────────────────────────────────────────────────────
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Project norms (commit conventions, etc.) detected from git history.
|
|
236
|
+
*/
|
|
237
|
+
function norms(basePath) {
|
|
238
|
+
return runQuery(basePath, ['norms']);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Commit message style + prefixes + scope usage.
|
|
243
|
+
*/
|
|
244
|
+
function conventions(basePath) {
|
|
245
|
+
return runQuery(basePath, ['conventions']);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// ─── Health ─────────────────────────────────────────────────────────────────
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Directory-level health overview.
|
|
252
|
+
*/
|
|
253
|
+
function areas(basePath) {
|
|
254
|
+
return runQuery(basePath, ['areas']);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Repository-wide health summary.
|
|
259
|
+
*/
|
|
260
|
+
function health(basePath) {
|
|
261
|
+
return runQuery(basePath, ['health']);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Release cadence and tag history.
|
|
266
|
+
*/
|
|
267
|
+
function releaseInfo(basePath) {
|
|
268
|
+
return runQuery(basePath, ['release-info']);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// ─── AI detection ───────────────────────────────────────────────────────────
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* AI vs human contribution ratio.
|
|
275
|
+
*/
|
|
276
|
+
function aiRatio(basePath, options = {}) {
|
|
277
|
+
const args = ['ai-ratio'];
|
|
278
|
+
if (options.pathFilter) args.push('--path-filter', options.pathFilter);
|
|
279
|
+
return runQuery(basePath, args);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Files with recent AI-authored changes.
|
|
284
|
+
*/
|
|
285
|
+
function recentAi(basePath, options = {}) {
|
|
286
|
+
const args = ['recent-ai'];
|
|
287
|
+
if (options.limit) args.push('--top', String(options.limit));
|
|
288
|
+
return runQuery(basePath, args);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// ─── Contributor guidance ───────────────────────────────────────────────────
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Newcomer-oriented repo summary (tech stack, key areas, pain points).
|
|
295
|
+
*/
|
|
296
|
+
function onboard(basePath) {
|
|
297
|
+
return runQuery(basePath, ['onboard']);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Contribution guidance: good-first areas, test gaps, doc drift, bugspots.
|
|
302
|
+
*/
|
|
303
|
+
function canIHelp(basePath) {
|
|
304
|
+
return runQuery(basePath, ['can-i-help']);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// ─── Documentation ──────────────────────────────────────────────────────────
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Doc files with low code coupling (likely stale).
|
|
311
|
+
*/
|
|
312
|
+
function docDrift(basePath, options = {}) {
|
|
313
|
+
const args = ['doc-drift'];
|
|
314
|
+
if (options.limit) args.push('--top', String(options.limit));
|
|
315
|
+
return runQuery(basePath, args);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Doc files with stale references to source symbols. Requires Phase 4
|
|
320
|
+
* sync-check data.
|
|
321
|
+
*/
|
|
322
|
+
function staleDocs(basePath, options = {}) {
|
|
323
|
+
const args = ['stale-docs'];
|
|
324
|
+
if (options.limit) args.push('--top', String(options.limit));
|
|
325
|
+
return runQuery(basePath, args);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// ─── AST symbols ────────────────────────────────────────────────────────────
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* AST symbols (exports, imports, definitions) for a specific file. Requires
|
|
332
|
+
* Phase 2 AST data.
|
|
333
|
+
*/
|
|
334
|
+
function symbols(basePath, file) {
|
|
335
|
+
return runQuery(basePath, ['symbols', file]);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Files that import a given symbol (reverse dependency lookup). Requires
|
|
340
|
+
* Phase 2 AST data.
|
|
341
|
+
*/
|
|
342
|
+
function dependents(basePath, symbol, file) {
|
|
343
|
+
const args = ['dependents', symbol];
|
|
344
|
+
if (file) args.push('--file', file);
|
|
345
|
+
return runQuery(basePath, args);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// ─── Phase 5: Graph-derived (analyzer-graph crate) ──────────────────────────
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Communities discovered by Louvain modularity over the co-change graph.
|
|
352
|
+
* Returns clusters of files that consistently change together - the natural
|
|
353
|
+
* feature areas, independent of directory layout. Requires agent-analyzer
|
|
354
|
+
* v0.4.0+.
|
|
355
|
+
*
|
|
356
|
+
* @param {string} basePath
|
|
357
|
+
* @returns {Array<{id: number, size: number, files: string[]}>}
|
|
358
|
+
*/
|
|
359
|
+
function communities(basePath) {
|
|
360
|
+
return runQuery(basePath, ['communities']);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Files bridging multiple communities (high betweenness centrality). These
|
|
365
|
+
* are the architectural seams - the highest-leverage files for refactoring
|
|
366
|
+
* decisions. Requires agent-analyzer v0.4.0+.
|
|
367
|
+
*
|
|
368
|
+
* @param {string} basePath
|
|
369
|
+
* @param {Object} [options={}]
|
|
370
|
+
* @param {number} [options.limit] - Maximum number of results
|
|
371
|
+
* @returns {Array<{path: string, betweenness: number, community: number|null}>}
|
|
372
|
+
*/
|
|
373
|
+
function boundaries(basePath, options = {}) {
|
|
374
|
+
const args = ['boundaries'];
|
|
375
|
+
if (options.limit) args.push('--top', String(options.limit));
|
|
376
|
+
return runQuery(basePath, args);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Look up which community a given file belongs to. Requires agent-analyzer
|
|
381
|
+
* v0.4.0+.
|
|
382
|
+
*
|
|
383
|
+
* @param {string} basePath
|
|
384
|
+
* @param {string} file - File path (relative to repo root)
|
|
385
|
+
* @returns {{file: string, community: number|null, size: number|null}}
|
|
386
|
+
*/
|
|
387
|
+
function areaOf(basePath, file) {
|
|
388
|
+
return runQuery(basePath, ['area-of', file]);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Composite per-community health: total/recent changes, bug-fix rate,
|
|
393
|
+
* AI ratio, stale-owner count. Use to identify communities under stress
|
|
394
|
+
* (high bug rate or stale ownership). Requires agent-analyzer v0.4.0+.
|
|
395
|
+
*
|
|
396
|
+
* @param {string} basePath
|
|
397
|
+
* @param {number} id - Community id (from `communities()`)
|
|
398
|
+
* @returns {Object|null}
|
|
399
|
+
*/
|
|
400
|
+
function communityHealth(basePath, id) {
|
|
401
|
+
if (!Number.isInteger(id) || id < 0) {
|
|
402
|
+
throw new TypeError(
|
|
403
|
+
`communityHealth: \`id\` must be a non-negative integer, got: ${id} (${typeof id})`
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
return runQuery(basePath, ['community-health', String(id)]);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
module.exports = {
|
|
410
|
+
// Errors
|
|
411
|
+
RepoIntelMissingError,
|
|
412
|
+
// Activity
|
|
413
|
+
hotspots,
|
|
414
|
+
coldspots,
|
|
415
|
+
fileHistory,
|
|
416
|
+
// Quality
|
|
417
|
+
bugspots,
|
|
418
|
+
testGaps,
|
|
419
|
+
diffRisk,
|
|
420
|
+
painspots,
|
|
421
|
+
// People
|
|
422
|
+
ownership,
|
|
423
|
+
contributors,
|
|
424
|
+
busFactor,
|
|
425
|
+
// Coupling
|
|
426
|
+
coupling,
|
|
427
|
+
// Standards
|
|
428
|
+
norms,
|
|
429
|
+
conventions,
|
|
430
|
+
// Health
|
|
431
|
+
areas,
|
|
432
|
+
health,
|
|
433
|
+
releaseInfo,
|
|
434
|
+
// AI detection
|
|
435
|
+
aiRatio,
|
|
436
|
+
recentAi,
|
|
437
|
+
// Contributor guidance
|
|
438
|
+
onboard,
|
|
439
|
+
canIHelp,
|
|
440
|
+
// Documentation
|
|
441
|
+
docDrift,
|
|
442
|
+
staleDocs,
|
|
443
|
+
// AST symbols
|
|
444
|
+
symbols,
|
|
445
|
+
dependents,
|
|
446
|
+
// Phase 5: graph-derived
|
|
447
|
+
communities,
|
|
448
|
+
boundaries,
|
|
449
|
+
areaOf,
|
|
450
|
+
communityHealth,
|
|
451
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentsys",
|
|
3
|
-
"version": "5.8.
|
|
3
|
+
"version": "5.8.6",
|
|
4
4
|
"description": "A modular runtime and orchestration system for AI agents - works with Claude Code, OpenCode, and Codex CLI",
|
|
5
5
|
"main": "lib/platform/detect-platform.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
"bump": "node bin/dev-cli.js bump",
|
|
38
38
|
"detect": "node bin/dev-cli.js detect",
|
|
39
39
|
"verify": "node bin/dev-cli.js verify",
|
|
40
|
-
"version": "node scripts/stamp-version.js && git add -
|
|
41
|
-
"
|
|
40
|
+
"version": "node scripts/stamp-version.js && git add package.json package-lock.json .claude-plugin/plugin.json .claude-plugin/marketplace.json site/content.json CHANGELOG.md",
|
|
41
|
+
"setup-hooks": "node bin/dev-cli.js setup-hooks"
|
|
42
42
|
},
|
|
43
43
|
"repository": {
|
|
44
44
|
"type": "git",
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
},
|
|
83
83
|
"dependencies": {
|
|
84
84
|
"agentsys": "^5.0.0",
|
|
85
|
-
"js-yaml": "
|
|
85
|
+
"js-yaml": "~4.1.1"
|
|
86
86
|
},
|
|
87
87
|
"devDependencies": {
|
|
88
88
|
"jest": "^29.7.0"
|
package/scripts/setup-hooks.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* Setup git hooks for development
|
|
4
|
-
* - pre-commit: Placeholder (lib/ sync handled by agent-core CI)
|
|
5
4
|
* - pre-push: Runs preflight checks, /enhance reminder, release validation
|
|
6
5
|
*/
|
|
7
6
|
|
|
@@ -9,13 +8,8 @@ const fs = require('fs');
|
|
|
9
8
|
const path = require('path');
|
|
10
9
|
|
|
11
10
|
const hookDir = path.join(__dirname, '..', '.git', 'hooks');
|
|
12
|
-
const preCommitPath = path.join(hookDir, 'pre-commit');
|
|
13
11
|
const prePushPath = path.join(hookDir, 'pre-push');
|
|
14
12
|
|
|
15
|
-
const preCommitHook = `#!/bin/sh
|
|
16
|
-
# Pre-commit hook (lib/ sync now handled by agent-core)
|
|
17
|
-
`;
|
|
18
|
-
|
|
19
13
|
const prePushHook = `#!/bin/sh
|
|
20
14
|
# Pre-push validations:
|
|
21
15
|
# 1. Run preflight checks (validators + gap checks)
|
|
@@ -135,14 +129,6 @@ function main() {
|
|
|
135
129
|
return 0;
|
|
136
130
|
}
|
|
137
131
|
|
|
138
|
-
try {
|
|
139
|
-
fs.writeFileSync(preCommitPath, preCommitHook, { mode: 0o755 });
|
|
140
|
-
console.log('Git pre-commit hook installed');
|
|
141
|
-
} catch (err) {
|
|
142
|
-
// Non-fatal - might not have write permissions
|
|
143
|
-
console.warn('Could not install pre-commit hook:', err.message);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
132
|
try {
|
|
147
133
|
fs.writeFileSync(prePushPath, prePushHook, { mode: 0o755 });
|
|
148
134
|
console.log('Git pre-push hook installed (release tag validation)');
|
package/site/content.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"url": "https://agent-sh.github.io/agentsys",
|
|
6
6
|
"repo": "https://github.com/agent-sh/agentsys",
|
|
7
7
|
"npm": "https://www.npmjs.com/package/agentsys",
|
|
8
|
-
"version": "5.8.
|
|
8
|
+
"version": "5.8.6",
|
|
9
9
|
"author": "Avi Fenesh",
|
|
10
10
|
"author_url": "https://github.com/avifenesh"
|
|
11
11
|
},
|