@brokkai/slopcop 0.0.7 → 0.0.9
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 +131 -15
- package/native/darwin_amd64/slopcop +0 -0
- package/native/darwin_arm64/slopcop +0 -0
- package/native/linux_amd64/slopcop +0 -0
- package/native/linux_arm64/slopcop +0 -0
- package/native/windows_amd64/slopcop.exe +0 -0
- package/native/windows_arm64/slopcop.exe +0 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,16 +25,17 @@ prompts, one request, and the analyzer's exit contract.
|
|
|
25
25
|
|
|
26
26
|
## Install
|
|
27
27
|
|
|
28
|
-
npm, PyPI, the release archive, and the PowerShell
|
|
29
|
-
same release binary for macOS, Linux, and Windows on x64 and
|
|
30
|
-
`slopcop version` reports which release it came from. The Go
|
|
31
|
-
build that binary from source instead.
|
|
28
|
+
npm, PyPI, the release archive, and the shell and PowerShell installers all
|
|
29
|
+
install the same release binary for macOS, Linux, and Windows on x64 and
|
|
30
|
+
arm64, so `slopcop version` reports which release it came from. The Go
|
|
31
|
+
toolchain can build that binary from source instead.
|
|
32
32
|
|
|
33
33
|
| Channel | Platforms | Needs |
|
|
34
34
|
| --- | --- | --- |
|
|
35
35
|
| [npm](#npm) | macOS, Linux, Windows | Node 22 or newer |
|
|
36
36
|
| [PyPI](#pypi) | macOS, Linux, Windows | Python 3.9 or newer |
|
|
37
37
|
| [Release archive](#release-archive) | macOS, Linux, Windows | nothing |
|
|
38
|
+
| [Shell installer](#shell-installer) | macOS, Linux | curl |
|
|
38
39
|
| [PowerShell installer](#powershell-installer) | Windows | PowerShell |
|
|
39
40
|
| [Go](#go) | built from source | Go 1.25 or newer |
|
|
40
41
|
|
|
@@ -78,6 +79,17 @@ tar -xzf "slopcop_v${ver}_${os}_${arch}.tar.gz" slopcop
|
|
|
78
79
|
sudo install -m 755 slopcop /usr/local/bin/slopcop
|
|
79
80
|
```
|
|
80
81
|
|
|
82
|
+
### Shell installer
|
|
83
|
+
|
|
84
|
+
```console
|
|
85
|
+
curl -fsSL https://raw.githubusercontent.com/BrokkAi/slopcop/master/install.sh | sh
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
It takes the latest release, verifies the archive against `checksums.txt`,
|
|
89
|
+
installs `slopcop` to `$HOME/.local/bin`, and adds that directory to the
|
|
90
|
+
shell profile. `SLOPCOP_VERSION`, `SLOPCOP_INSTALL_DIR`, and
|
|
91
|
+
`SLOPCOP_NO_MODIFY_PATH` override its defaults.
|
|
92
|
+
|
|
81
93
|
### PowerShell installer
|
|
82
94
|
|
|
83
95
|
```powershell
|
|
@@ -89,6 +101,25 @@ installs `slopcop.exe` to `%LOCALAPPDATA%\Programs\slopcop`, and adds that
|
|
|
89
101
|
directory to the user `Path`. `SLOPCOP_VERSION`, `SLOPCOP_INSTALL_DIR`, and
|
|
90
102
|
`SLOPCOP_NO_MODIFY_PATH` override its defaults.
|
|
91
103
|
|
|
104
|
+
### Upgrade notice
|
|
105
|
+
|
|
106
|
+
Every response from the service names its newest release in the
|
|
107
|
+
`SlopCop-Latest-Version` header. When that is newer than the running build,
|
|
108
|
+
the CLI prints one line on stderr, never stdout, so `--format json` and
|
|
109
|
+
`sarif` stay clean:
|
|
110
|
+
|
|
111
|
+
```text
|
|
112
|
+
slopcop v0.0.9 is available (you have v0.0.7). Upgrade: npm install --global @brokkai/slopcop@latest
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The command follows the channel the binary was installed through (npm, npx,
|
|
116
|
+
pip, pipx, or uv), judged by where it lives, and links back here otherwise.
|
|
117
|
+
The notice prints at most once a day; the time of the last one is kept in
|
|
118
|
+
`slopcop/update-notice` next to the config. `dev` builds, `Stop` hook runs, and
|
|
119
|
+
runs with `$SLOPCOP_NO_UPDATE_NOTICE` set to any non-empty value never print
|
|
120
|
+
it. A service that no longer accepts a version answers `client_outdated`
|
|
121
|
+
(HTTP 426), which exits `2`.
|
|
122
|
+
|
|
92
123
|
### Go
|
|
93
124
|
|
|
94
125
|
```console
|
|
@@ -101,8 +132,9 @@ its version; in a clone, `make install` stamps the version from `git describe`.
|
|
|
101
132
|
## Enable it in an agent
|
|
102
133
|
|
|
103
134
|
The binary carries the agent skill that teaches a coding agent how to run
|
|
104
|
-
slopcop
|
|
105
|
-
|
|
135
|
+
slopcop, plus an automatic check hook for Claude Code and Codex. `slopcop init`
|
|
136
|
+
installs the skill into each well-known skills directory whose harness is
|
|
137
|
+
present, and names what it did:
|
|
106
138
|
|
|
107
139
|
| Location | Harness |
|
|
108
140
|
| --- | --- |
|
|
@@ -117,6 +149,47 @@ so an agent follows the instructions of the slopcop version it runs; local
|
|
|
117
149
|
edits to an installed skill do not survive them. `slopcop init --no-skill`
|
|
118
150
|
skips the install and any update of it.
|
|
119
151
|
|
|
152
|
+
Init also adds a `Stop` hook for each harness installed here, and leaves
|
|
153
|
+
everything else in the file as it was:
|
|
154
|
+
|
|
155
|
+
| File | Harness |
|
|
156
|
+
| --- | --- |
|
|
157
|
+
| `settings.json` under `CLAUDE_CONFIG_DIR`, or `~/.claude` | Claude Code |
|
|
158
|
+
| `hooks.json` under `CODEX_HOME`, or `~/.codex` | Codex |
|
|
159
|
+
|
|
160
|
+
Codex runs a new or changed hook only once you trust it: open Codex and review
|
|
161
|
+
it with `/hooks`. Init never writes that trust itself, and reminds you each
|
|
162
|
+
time it runs, since Codex says nothing of a hook it skips. The hook stays the
|
|
163
|
+
same from one release to the next, so an update does not ask for it again.
|
|
164
|
+
|
|
165
|
+
When the agent stops, the hook checks the working tree through the same
|
|
166
|
+
hosted API, but only when all of these hold:
|
|
167
|
+
|
|
168
|
+
- the session wrote files in the repository with its edit tools (a Codex
|
|
169
|
+
session's subagents included);
|
|
170
|
+
- slopcop is signed in, and the workspace a check would use
|
|
171
|
+
(`$SLOPCOP_WORKSPACE`, or the login's) has the repository active
|
|
172
|
+
(`slopcop repo list`), so nothing is sent from other repositories;
|
|
173
|
+
- the tree differs from the last check in the session, including a check the
|
|
174
|
+
agent ran by hand.
|
|
175
|
+
|
|
176
|
+
New findings in files the session wrote are handed to the agent to fix, once
|
|
177
|
+
for a given tree and at most twice in a row; then the agent is let go and you
|
|
178
|
+
are told what remains. A finding ignored with `slopcop ignore` is not handed
|
|
179
|
+
back. New findings in other files on the branch are only mentioned. The hook
|
|
180
|
+
never keeps the agent going on its own failures: a refusal the service calls
|
|
181
|
+
final, such as an expired login, is reported once and the hook stays quiet for
|
|
182
|
+
the rest of the session, until a check by hand completes; a brief outage is
|
|
183
|
+
only reported. The hook runs as `slopcop hook claude || true` (and
|
|
184
|
+
`slopcop hook codex || true`, or `|| exit /b 0` under Windows' `cmd`), so even
|
|
185
|
+
a `slopcop` that cannot run it, such as an older one first on `PATH`, lets the
|
|
186
|
+
agent stop; init warns when that is the case, because no check would run.
|
|
187
|
+
|
|
188
|
+
Use `slopcop init --no-hooks` to install only the skill, or
|
|
189
|
+
`slopcop init --remove-hooks` to remove SlopCop's hooks and nothing else.
|
|
190
|
+
Ordinary checks do not reinstall a removed hook. The skill remains the way to
|
|
191
|
+
check from other harnesses.
|
|
192
|
+
|
|
120
193
|
## Sign in
|
|
121
194
|
|
|
122
195
|
```console
|
|
@@ -137,6 +210,7 @@ Precedence:
|
|
|
137
210
|
| --- | --- |
|
|
138
211
|
| Service URL | `--service`, `$SLOPCOP_SERVICE`, stored by `slopcop login`, `https://slopcop.com` |
|
|
139
212
|
| Token | `$SLOPCOP_TOKEN`, stored value |
|
|
213
|
+
| Workspace (`check`, `ignore`, `repo`) | `-w`/`--workspace`, `$SLOPCOP_WORKSPACE`, the one the login is bound to |
|
|
140
214
|
|
|
141
215
|
## Workspace and repositories
|
|
142
216
|
|
|
@@ -147,6 +221,7 @@ active in the browser when the login was approved.
|
|
|
147
221
|
slopcop whoami # account, this login's workspace, its plan, the service URL
|
|
148
222
|
slopcop workspace list # the account's workspaces; * marks this login's
|
|
149
223
|
slopcop workspace use "Acme team" # move this login (not the browser) to another, by name or id
|
|
224
|
+
slopcop check -w "Acme team" # check in, and bill, another workspace this once
|
|
150
225
|
slopcop repo list # the workspace's repositories: active, disabled, or over the limit
|
|
151
226
|
slopcop repo disable acme/widgets # stop checking and charging for one (owner only)
|
|
152
227
|
slopcop repo enable acme/widgets # turn it back on, within the workspace's active limit
|
|
@@ -160,9 +235,23 @@ one is not checked or charged and keeps its reports, findings and settings.
|
|
|
160
235
|
and refuse when stdin is not a terminal: an agent or CI job runs with your
|
|
161
236
|
login, and the service cannot tell it from you, so changing what the workspace
|
|
162
237
|
pays stays a step you take yourself.
|
|
238
|
+
`workspace use` moves every agent and script using this login, not only the
|
|
239
|
+
one that runs it, so it asks `[y/N]` and refuses when stdin is not a terminal.
|
|
240
|
+
To check in another workspace without moving anyone, `check`, `ignore` and
|
|
241
|
+
`repo` take `-w`/`--workspace <name|id>` (or `$SLOPCOP_WORKSPACE`) for that one
|
|
242
|
+
command; the login stays where it was. Give agents that share a login their
|
|
243
|
+
own `--workspace` instead of switching it.
|
|
244
|
+
|
|
163
245
|
Names match without regard to case; when two workspaces share a name, or two
|
|
164
246
|
providers a repository name, pass the id the listing prints. There is no `repo
|
|
165
|
-
add`: a first check adds a repository.
|
|
247
|
+
add`: a first check adds a repository. When the workspace would then pay for
|
|
248
|
+
it (it already has an active repository and is charged), the service refuses
|
|
249
|
+
the check with `repository_add_unconfirmed` until a person confirms: at a
|
|
250
|
+
terminal `check` prints what it costs, asks `Add owner/name to "Workspace"?
|
|
251
|
+
[y/N]`, and on a yes sends the check again; with no terminal, as for an agent
|
|
252
|
+
or CI, it exits `4` with the service's remedy and, in `json`, a `failed`
|
|
253
|
+
report naming the code. A workspace's first repository
|
|
254
|
+
is added without asking. Deleting repositories, archiving
|
|
166
255
|
workspaces, members, credits and repository settings stay in the web app. The
|
|
167
256
|
commands exit `0` on success and `2` with the service's message and remedy
|
|
168
257
|
otherwise, as `ignore` does.
|
|
@@ -176,13 +265,19 @@ slopcop --root ../repo --base HEAD~1
|
|
|
176
265
|
```
|
|
177
266
|
|
|
178
267
|
The base commit defaults to the merge base with the branch upstream, then the
|
|
179
|
-
merge base with `origin/HEAD`, then `HEAD
|
|
268
|
+
merge base with `origin/HEAD`, then `HEAD` when neither is known. When the
|
|
269
|
+
upstream merge base yields an empty patch, as on a branch whose commits are all
|
|
270
|
+
pushed, the CLI uses the merge base with `origin/HEAD` instead, so a check
|
|
271
|
+
right after a push still covers the branch. The service must already have the
|
|
180
272
|
base commit in its clone; a missing one comes back as the service's
|
|
181
273
|
`base_not_found` message and remedy.
|
|
182
274
|
|
|
183
275
|
Every run sends one check request, even when the working tree matches the base
|
|
184
276
|
and the patch is empty. A clean result or a failure always comes from the
|
|
185
|
-
service.
|
|
277
|
+
service. A report for an empty patch comes with a note on stderr that suggests
|
|
278
|
+
`--base`, and `json` adds `"emptyChange": true` (`sarif`:
|
|
279
|
+
`properties["slopcop.emptyChange"]`): a clean result then means nothing
|
|
280
|
+
changed was checked.
|
|
186
281
|
|
|
187
282
|
Flags:
|
|
188
283
|
|
|
@@ -195,6 +290,7 @@ Flags:
|
|
|
195
290
|
| `--policy PATH` | repository-relative `.rqlp` file to evaluate (repeatable) |
|
|
196
291
|
| `--no-policy-discovery` | skip `.slopcop/policies` rules |
|
|
197
292
|
| `--timeout DURATION` | how long to wait for the result (default `10m`) |
|
|
293
|
+
| `-w`, `--workspace NAME\|ID` | check in, and bill, this workspace of the account instead of the login's |
|
|
198
294
|
| `--verbose` | print the resolved request to stderr |
|
|
199
295
|
|
|
200
296
|
### What is sent
|
|
@@ -272,8 +368,8 @@ summary line such as `1 new finding across 1 file(s); 72 already in the code |
|
|
|
272
368
|
Analysis complete`, and any omitted new findings or
|
|
273
369
|
incomplete checks. `json` prints `status`, `baseCommit`, `summary`
|
|
274
370
|
(`newFindings` and `existingFindings` count the split), `findings` (each with
|
|
275
|
-
`new` and its `id`), `incomplete`,
|
|
276
|
-
complete. `sarif` prints a SARIF 2.1.0 log whose results carry `baselineState`
|
|
371
|
+
`new` and its `id`), `incomplete`, `failure` when the analysis did not
|
|
372
|
+
complete, and `emptyChange` when the patch was empty. `sarif` prints a SARIF 2.1.0 log whose results carry `baselineState`
|
|
277
373
|
`new` and the finding id in `properties["slopcop.findingId"]`. `--format` only
|
|
278
374
|
changes the rendering, never the request, so the service answers the same check
|
|
279
375
|
whichever is used.
|
|
@@ -284,6 +380,7 @@ whichever is used.
|
|
|
284
380
|
| `1` | A new finding crossed `--fail-on` |
|
|
285
381
|
| `2` | No new finding crossed `--fail-on`, but a check was incomplete; or the CLI or service failed |
|
|
286
382
|
| `3` | The check was still running when `--timeout` ran out |
|
|
383
|
+
| `4` | The service refused the check, and only a person can clear it |
|
|
287
384
|
| `130`, `143` | Interrupted before the check answered: `130` for Ctrl-C, `143` for SIGTERM |
|
|
288
385
|
|
|
289
386
|
Only `clean` exits `0`: a status this CLI does not know exits `2`, so a newer
|
|
@@ -323,8 +420,21 @@ rewrite them. The remedies name no client, so the CLI adds its own command
|
|
|
323
420
|
after some: `slopcop login` when the remedy is to sign in, the listing to
|
|
324
421
|
choose from after `workspace_not_found` or `workspace_repository_not_found`,
|
|
325
422
|
and `slopcop whoami` after `repository_disabled`, since the workspace that
|
|
326
|
-
disabled it is the one this login is bound to
|
|
327
|
-
|
|
423
|
+
disabled it is the one this login is bound to, and `--workspace` after
|
|
424
|
+
`owner_required`. A failed check exits `4` when only a person can clear the
|
|
425
|
+
refusal (`auth_required`, `auth_expired`, `account_required`,
|
|
426
|
+
`repo_not_indexed`, `app_not_installed`, `app_no_repo_access`,
|
|
427
|
+
`gitlab_not_connected`, `no_access`, `insufficient_credits`,
|
|
428
|
+
`repository_disabled`, `repository_add_unconfirmed`,
|
|
429
|
+
`workspace_repository_limit_reached`, `active_repository_limit_reached`,
|
|
430
|
+
`owner_required`, and `browser_required`), so a script can stop instead of
|
|
431
|
+
retrying, and `2` otherwise. Stderr starts with the code, as in `slopcop:
|
|
432
|
+
repository_add_unconfirmed: …`. `human` prints nothing on stdout; `json`
|
|
433
|
+
prints `{"status": "failed", "code": …, "message": …, "remedy": …,
|
|
434
|
+
"retryable": …}`, plus `installUrl` or `topUpUrl` when the service sent one;
|
|
435
|
+
`sarif` prints a run with `slopcop.status` `failed`, whose invocation is
|
|
436
|
+
unsuccessful and carries an `error` notification whose descriptor id is the
|
|
437
|
+
code.
|
|
328
438
|
|
|
329
439
|
## API
|
|
330
440
|
|
|
@@ -336,11 +446,16 @@ The CLI calls `POST <service>/v1/check` with a bearer token:
|
|
|
336
446
|
"baseCommit": "0123456789abcdef0123456789abcdef01234567",
|
|
337
447
|
"change": "<base64 git patch>",
|
|
338
448
|
"selection": {"files": [".slopcop/policies/rule.rqlp"]},
|
|
339
|
-
"failOn": "finding"
|
|
449
|
+
"failOn": "finding",
|
|
450
|
+
"addRepository": true
|
|
340
451
|
}
|
|
341
452
|
```
|
|
342
453
|
|
|
343
|
-
|
|
454
|
+
`addRepository` is sent only after a person confirms adding the repository. The
|
|
455
|
+
service rejects any other field. With `--workspace`, every request, the
|
|
456
|
+
check's, the ignore's and the account routes', carries the workspace's id in
|
|
457
|
+
the `SlopCop-Workspace` header; a name is first looked up with
|
|
458
|
+
`GET <service>/v1/whoami`. The response carries `status`,
|
|
344
459
|
`baseCommit`, `applied`, `summary`, `findings`, `incomplete`, and `failure`
|
|
345
460
|
when the analysis did not complete. Against a service from before findings
|
|
346
461
|
were marked `new`, the CLI treats every finding as new, as that service gated
|
|
@@ -414,6 +529,7 @@ Layout:
|
|
|
414
529
|
| `internal/service` | `/v1/check` client and the wire contract |
|
|
415
530
|
| `internal/report` | human, JSON, and SARIF rendering from the structured response |
|
|
416
531
|
| `internal/config` | stored service URL and token |
|
|
532
|
+
| `internal/hooks` | Claude Code and Codex hook installation and removal |
|
|
417
533
|
| `npm` | launcher, packer, and tests of the `@brokkai/slopcop` package |
|
|
418
534
|
| `packaging/pypi` | wheel packer and launcher of the `brokk-slopcop` package |
|
|
419
535
|
| `skills/slopcop` | the agent skill the binary embeds and installs |
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|