@brokkai/slopcop 0.0.6 → 0.0.8

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 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 installer all install the
29
- same release binary for macOS, Linux, and Windows on x64 and arm64, so
30
- `slopcop version` reports which release it came from. The Go toolchain can
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
@@ -101,8 +113,9 @@ its version; in a clone, `make install` stamps the version from `git describe`.
101
113
  ## Enable it in an agent
102
114
 
103
115
  The binary carries the agent skill that teaches a coding agent how to run
104
- slopcop. `slopcop init` installs it into each well-known skills directory whose
105
- harness is present, and names what it did:
116
+ slopcop, plus an automatic check hook for Claude Code and Codex. `slopcop init`
117
+ installs the skill into each well-known skills directory whose harness is
118
+ present, and names what it did:
106
119
 
107
120
  | Location | Harness |
108
121
  | --- | --- |
@@ -117,6 +130,47 @@ so an agent follows the instructions of the slopcop version it runs; local
117
130
  edits to an installed skill do not survive them. `slopcop init --no-skill`
118
131
  skips the install and any update of it.
119
132
 
133
+ Init also adds a `Stop` hook for each harness installed here, and leaves
134
+ everything else in the file as it was:
135
+
136
+ | File | Harness |
137
+ | --- | --- |
138
+ | `settings.json` under `CLAUDE_CONFIG_DIR`, or `~/.claude` | Claude Code |
139
+ | `hooks.json` under `CODEX_HOME`, or `~/.codex` | Codex |
140
+
141
+ Codex runs a new or changed hook only once you trust it: open Codex and review
142
+ it with `/hooks`. Init never writes that trust itself, and reminds you each
143
+ time it runs, since Codex says nothing of a hook it skips. The hook stays the
144
+ same from one release to the next, so an update does not ask for it again.
145
+
146
+ When the agent stops, the hook checks the working tree through the same
147
+ hosted API, but only when all of these hold:
148
+
149
+ - the session wrote files in the repository with its edit tools (a Codex
150
+ session's subagents included);
151
+ - slopcop is signed in, and the workspace a check would use
152
+ (`$SLOPCOP_WORKSPACE`, or the login's) has the repository active
153
+ (`slopcop repo list`), so nothing is sent from other repositories;
154
+ - the tree differs from the last check in the session, including a check the
155
+ agent ran by hand.
156
+
157
+ New findings in files the session wrote are handed to the agent to fix, once
158
+ for a given tree and at most twice in a row; then the agent is let go and you
159
+ are told what remains. A finding ignored with `slopcop ignore` is not handed
160
+ back. New findings in other files on the branch are only mentioned. The hook
161
+ never keeps the agent going on its own failures: a refusal the service calls
162
+ final, such as an expired login, is reported once and the hook stays quiet for
163
+ the rest of the session, until a check by hand completes; a brief outage is
164
+ only reported. The hook runs as `slopcop hook claude || true` (and
165
+ `slopcop hook codex || true`, or `|| exit /b 0` under Windows' `cmd`), so even
166
+ a `slopcop` that cannot run it, such as an older one first on `PATH`, lets the
167
+ agent stop; init warns when that is the case, because no check would run.
168
+
169
+ Use `slopcop init --no-hooks` to install only the skill, or
170
+ `slopcop init --remove-hooks` to remove SlopCop's hooks and nothing else.
171
+ Ordinary checks do not reinstall a removed hook. The skill remains the way to
172
+ check from other harnesses.
173
+
120
174
  ## Sign in
121
175
 
122
176
  ```console
@@ -137,6 +191,7 @@ Precedence:
137
191
  | --- | --- |
138
192
  | Service URL | `--service`, `$SLOPCOP_SERVICE`, stored by `slopcop login`, `https://slopcop.com` |
139
193
  | Token | `$SLOPCOP_TOKEN`, stored value |
194
+ | Workspace (`check`, `ignore`, `repo`) | `-w`/`--workspace`, `$SLOPCOP_WORKSPACE`, the one the login is bound to |
140
195
 
141
196
  ## Workspace and repositories
142
197
 
@@ -147,6 +202,7 @@ active in the browser when the login was approved.
147
202
  slopcop whoami # account, this login's workspace, its plan, the service URL
148
203
  slopcop workspace list # the account's workspaces; * marks this login's
149
204
  slopcop workspace use "Acme team" # move this login (not the browser) to another, by name or id
205
+ slopcop check -w "Acme team" # check in, and bill, another workspace this once
150
206
  slopcop repo list # the workspace's repositories: active, disabled, or over the limit
151
207
  slopcop repo disable acme/widgets # stop checking and charging for one (owner only)
152
208
  slopcop repo enable acme/widgets # turn it back on, within the workspace's active limit
@@ -160,9 +216,22 @@ one is not checked or charged and keeps its reports, findings and settings.
160
216
  and refuse when stdin is not a terminal: an agent or CI job runs with your
161
217
  login, and the service cannot tell it from you, so changing what the workspace
162
218
  pays stays a step you take yourself.
219
+ `workspace use` moves every agent and script using this login, not only the
220
+ one that runs it, so it asks `[y/N]` and refuses when stdin is not a terminal.
221
+ To check in another workspace without moving anyone, `check`, `ignore` and
222
+ `repo` take `-w`/`--workspace <name|id>` (or `$SLOPCOP_WORKSPACE`) for that one
223
+ command; the login stays where it was. Give agents that share a login their
224
+ own `--workspace` instead of switching it.
225
+
163
226
  Names match without regard to case; when two workspaces share a name, or two
164
227
  providers a repository name, pass the id the listing prints. There is no `repo
165
- add`: a first check adds a repository. Deleting repositories, archiving
228
+ add`: a first check adds a repository. When the workspace would then pay for
229
+ it (it already has an active repository and is charged), the service refuses
230
+ the check with `repository_add_unconfirmed` until a person confirms: at a
231
+ terminal `check` prints what it costs, asks `Add owner/name to "Workspace"?
232
+ [y/N]`, and on a yes sends the check again; with no terminal, as for an agent
233
+ or CI, it exits `2` with the service's remedy. A workspace's first repository
234
+ is added without asking. Deleting repositories, archiving
166
235
  workspaces, members, credits and repository settings stay in the web app. The
167
236
  commands exit `0` on success and `2` with the service's message and remedy
168
237
  otherwise, as `ignore` does.
@@ -195,6 +264,7 @@ Flags:
195
264
  | `--policy PATH` | repository-relative `.rqlp` file to evaluate (repeatable) |
196
265
  | `--no-policy-discovery` | skip `.slopcop/policies` rules |
197
266
  | `--timeout DURATION` | how long to wait for the result (default `10m`) |
267
+ | `-w`, `--workspace NAME\|ID` | check in, and bill, this workspace of the account instead of the login's |
198
268
  | `--verbose` | print the resolved request to stderr |
199
269
 
200
270
  ### What is sent
@@ -269,7 +339,7 @@ check outside your workspace.
269
339
  The service answers structured data; the CLI renders it. `human` prints one
270
340
  block per new finding, with an `ID:` line when the service names one, then a
271
341
  summary line such as `1 new finding across 1 file(s); 72 already in the code |
272
- Analysis complete`, and any omitted or
342
+ Analysis complete`, and any omitted new findings or
273
343
  incomplete checks. `json` prints `status`, `baseCommit`, `summary`
274
344
  (`newFindings` and `existingFindings` count the split), `findings` (each with
275
345
  `new` and its `id`), `incomplete`, and `failure` when the analysis did not
@@ -292,12 +362,12 @@ interrupted check prints no report. Interrupted before it was sent, nothing
292
362
  reached the service; after, a service that received it keeps running it, and
293
363
  running the same check again picks up its result.
294
364
 
295
- An inconclusive check fails the check only when it concerns a file the
296
- change writes. One about other files is listed on an `Inconclusive outside
297
- the change` line (`inconclusiveElsewhere` in `json`, a `note` notification in
298
- `sarif`) and never changes the exit code. A check that timed out counts
299
- wherever it is. The service can place an inconclusive check only once Bifrost
300
- reports which files it concerns; until then every one counts as in the change.
365
+ An inconclusive check, one that ran but could not prove there is nothing
366
+ more to find, never changes the exit code and is not named in any format.
367
+ Complete proof is rare in static analysis, typically at a library boundary,
368
+ so this is the norm rather than a gap. `summary.inconclusive` counts them in
369
+ `json`, as does `slopcop.inconclusive` in `sarif`. A check that timed out or
370
+ that Bifrost judged unreliable is incomplete and counts wherever it is.
301
371
 
302
372
  The service applies `--fail-on` and sets the status; the exit code follows it.
303
373
  The CLI always sends `--fail-on`, defaulting to `finding`: a check fails only
@@ -323,7 +393,8 @@ rewrite them. The remedies name no client, so the CLI adds its own command
323
393
  after some: `slopcop login` when the remedy is to sign in, the listing to
324
394
  choose from after `workspace_not_found` or `workspace_repository_not_found`,
325
395
  and `slopcop whoami` after `repository_disabled`, since the workspace that
326
- disabled it is the one this login is bound to. A failed request prints no
396
+ disabled it is the one this login is bound to, and `--workspace` after
397
+ `owner_required`. A failed request prints no
327
398
  report on stdout.
328
399
 
329
400
  ## API
@@ -336,11 +407,16 @@ The CLI calls `POST <service>/v1/check` with a bearer token:
336
407
  "baseCommit": "0123456789abcdef0123456789abcdef01234567",
337
408
  "change": "<base64 git patch>",
338
409
  "selection": {"files": [".slopcop/policies/rule.rqlp"]},
339
- "failOn": "finding"
410
+ "failOn": "finding",
411
+ "addRepository": true
340
412
  }
341
413
  ```
342
414
 
343
- The service rejects any other field. The response carries `status`,
415
+ `addRepository` is sent only after a person confirms adding the repository. The
416
+ service rejects any other field. With `--workspace`, every request, the
417
+ check's, the ignore's and the account routes', carries the workspace's id in
418
+ the `SlopCop-Workspace` header; a name is first looked up with
419
+ `GET <service>/v1/whoami`. The response carries `status`,
344
420
  `baseCommit`, `applied`, `summary`, `findings`, `incomplete`, and `failure`
345
421
  when the analysis did not complete. Against a service from before findings
346
422
  were marked `new`, the CLI treats every finding as new, as that service gated
@@ -414,6 +490,7 @@ Layout:
414
490
  | `internal/service` | `/v1/check` client and the wire contract |
415
491
  | `internal/report` | human, JSON, and SARIF rendering from the structured response |
416
492
  | `internal/config` | stored service URL and token |
493
+ | `internal/hooks` | Claude Code and Codex hook installation and removal |
417
494
  | `npm` | launcher, packer, and tests of the `@brokkai/slopcop` package |
418
495
  | `packaging/pypi` | wheel packer and launcher of the `brokk-slopcop` package |
419
496
  | `skills/slopcop` | the agent skill the binary embeds and installs |
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brokkai/slopcop",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "description": "Static analysis for coding agents and CI: check a change through the hosted SlopCop API",
5
5
  "keywords": [
6
6
  "agents",