@brokkai/slopcop 0.0.4 → 0.0.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/README.md CHANGED
@@ -110,9 +110,12 @@ harness is present, and names what it did:
110
110
  | `~/.claude/skills/slopcop/` | Claude Code, opencode |
111
111
  | `$CODEX_HOME/skills/slopcop/`, or `~/.codex/skills/slopcop/` | Codex home |
112
112
 
113
- A skill that is already there is left alone, so local edits survive and running
114
- init again is safe. `slopcop init --no-skill` skips the install and any update
115
- of it.
113
+ A skill that is already there is left alone by init, so running it again is
114
+ safe. `slopcop login` and every check also install the skill in those
115
+ directories, rewriting one that differs from the skill bundled into the binary,
116
+ so an agent follows the instructions of the slopcop version it runs; local
117
+ edits to an installed skill do not survive them. `slopcop init --no-skill`
118
+ skips the install and any update of it.
116
119
 
117
120
  ## Sign in
118
121
 
@@ -135,6 +138,35 @@ Precedence:
135
138
  | Service URL | `--service`, `$SLOPCOP_SERVICE`, stored by `slopcop login`, `https://slopcop.com` |
136
139
  | Token | `$SLOPCOP_TOKEN`, stored value |
137
140
 
141
+ ## Workspace and repositories
142
+
143
+ A login runs its checks and ignores in, and bills, one workspace: the one
144
+ active in the browser when the login was approved.
145
+
146
+ ```console
147
+ slopcop whoami # account, this login's workspace, its plan, the service URL
148
+ slopcop workspace list # the account's workspaces; * marks this login's
149
+ slopcop workspace use "Acme team" # move this login (not the browser) to another, by name or id
150
+ slopcop repo list # the workspace's repositories: active, disabled, or over the limit
151
+ slopcop repo disable acme/widgets # stop checking and charging for one (owner only)
152
+ slopcop repo enable acme/widgets # turn it back on, within the workspace's active limit
153
+ ```
154
+
155
+ `whoami`, `workspace list` and `repo list` take `--format human|json`, as do
156
+ `workspace use` and `repo enable|disable` for their answer. Every active
157
+ repository after a workspace's first costs credits every 30 days; a disabled
158
+ one is not checked or charged and keeps its reports, findings and settings.
159
+ `repo enable` and `repo disable` ask you to type the repository's `owner/name`
160
+ and refuse when stdin is not a terminal: an agent or CI job runs with your
161
+ login, and the service cannot tell it from you, so changing what the workspace
162
+ pays stays a step you take yourself.
163
+ Names match without regard to case; when two workspaces share a name, or two
164
+ 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
166
+ workspaces, members, credits and repository settings stay in the web app. The
167
+ commands exit `0` on success and `2` with the service's message and remedy
168
+ otherwise, as `ignore` does.
169
+
138
170
  ## Check
139
171
 
140
172
  ```console
@@ -160,7 +192,6 @@ Flags:
160
192
  | `--base REV` | base commit or revision for the change |
161
193
  | `--format human\|json\|sarif` | report format (default `human`) |
162
194
  | `--fail-on never\|finding\|note\|warning\|error` | exit-1 threshold for new findings (default `finding`) |
163
- | `--show-existing` | also list the findings that were already in the code |
164
195
  | `--policy PATH` | repository-relative `.rqlp` file to evaluate (repeatable) |
165
196
  | `--no-policy-discovery` | skip `.slopcop/policies` rules |
166
197
  | `--timeout DURATION` | how long to wait for the result (default `10m`) |
@@ -175,6 +206,26 @@ changes, and binary content. Git-ignored files stay out, except selected
175
206
  `.slopcop/policies` rules, which must travel because the service evaluates them
176
207
  from the patched checkout.
177
208
 
209
+ A check run by a Claude Code or Codex agent also sends which models wrote the
210
+ change, so the service can tie each finding to the model that wrote its file.
211
+ The CLI finds the agent's session from its environment and reads that
212
+ session's own record:
213
+
214
+ - **Claude Code:** `CLAUDE_CODE_SESSION_ID` names the transcript under
215
+ `~/.claude/projects` (or `$CLAUDE_CONFIG_DIR/projects`), subagents included.
216
+ Each successful Write, Edit, MultiEdit or NotebookEdit gives a model, an
217
+ effort and a file.
218
+ - **Codex:** `CODEX_THREAD_ID` names the rollout under `~/.codex/sessions` (or
219
+ `$CODEX_HOME/sessions`). Each completed file change gives the files, and its
220
+ turn gives the model and effort. A move counts as writing its destination.
221
+
222
+ It reads only those fields, never the conversation, tool input or file
223
+ contents. What it sends is the harness, its version, the session id as an
224
+ opaque identifier, and each model and effort with the repository-relative
225
+ files it wrote. A check run outside an agent session sends none of this. It
226
+ is analytics only, asserted by the client, and never decides a check.
227
+ `--verbose` prints it.
228
+
178
229
  The service owns the limits on what a check accepts. When a change is too
179
230
  large or touches too many files, the service's `payload_too_large` response is
180
231
  printed verbatim; the CLI does not impose its own limits.
@@ -188,22 +239,44 @@ Every check also runs the hosted catalog. Rules under
188
239
  A check fails only on findings the change introduced or touched: the service
189
240
  marks a finding new when it is in a file the change writes and its lines meet a
190
241
  line the change added, or the line beside one it removed. Findings that were
191
- already in the code are counted, never fail the check, and are listed only with
192
- `--show-existing`. A change that introduces nothing exits `0`, however many
193
- findings the repository already holds.
242
+ already in the code are counted (`summary.existingFindings`, and `N already in
243
+ the code` in the human summary), never fail the check, and are not listed. A
244
+ change that introduces nothing exits `0`, however many findings the repository
245
+ already holds. `--show-existing` is deprecated and hidden: the service no longer
246
+ sends those findings, so against it the flag lists nothing (a service from
247
+ before that still gets them listed), and it stays so that scripts passing it
248
+ keep running.
249
+
250
+ ### Ignore a false positive
251
+
252
+ Each finding a check reports carries an `id`. When a finding is a false
253
+ positive, ignore it:
254
+
255
+ ```console
256
+ slopcop ignore 0f8fad5b-d9cb-469f-a165-70867728950e
257
+ ```
258
+
259
+ That finding is not reported again for this repository. Ignoring covers that
260
+ one finding, its rule plus its place in the code, in its repository for your
261
+ workspace; the rule keeps reporting everything else. Ignoring a finding twice
262
+ is fine. `ignore` uses the same login and service URL as a check, exits `0`
263
+ with a one-line confirmation, and otherwise exits `2` with the service's
264
+ message and remedy; `finding_not_found` means the id is unknown or comes from a
265
+ check outside your workspace.
194
266
 
195
267
  ### Output and exit codes
196
268
 
197
269
  The service answers structured data; the CLI renders it. `human` prints one
198
- block per new finding, then the pre-existing ones with `--show-existing`, a
199
- summary line such as `1 new finding across 1 file(s); 72 already in the code
200
- (--show-existing lists them) | Analysis complete`, and any omitted or
270
+ block per new finding, with an `ID:` line when the service names one, then a
271
+ summary line such as `1 new finding across 1 file(s); 72 already in the code |
272
+ Analysis complete`, and any omitted or
201
273
  incomplete checks. `json` prints `status`, `baseCommit`, `summary`
202
274
  (`newFindings` and `existingFindings` count the split), `findings` (each with
203
- `new`), `incomplete`, and `failure` when the analysis did not complete. `sarif`
204
- prints a SARIF 2.1.0 log whose results carry `baselineState` `new` or
205
- `unchanged`. `--format` and `--show-existing` only change the rendering, never
206
- the request, so the service answers the same check whichever is used.
275
+ `new` and its `id`), `incomplete`, and `failure` when the analysis did not
276
+ complete. `sarif` prints a SARIF 2.1.0 log whose results carry `baselineState`
277
+ `new` and the finding id in `properties["slopcop.findingId"]`. `--format` only
278
+ changes the rendering, never the request, so the service answers the same check
279
+ whichever is used.
207
280
 
208
281
  | Exit | Meaning |
209
282
  | --- | --- |
@@ -211,6 +284,13 @@ the request, so the service answers the same check whichever is used.
211
284
  | `1` | A new finding crossed `--fail-on` |
212
285
  | `2` | No new finding crossed `--fail-on`, but a check was incomplete; or the CLI or service failed |
213
286
  | `3` | The check was still running when `--timeout` ran out |
287
+ | `130`, `143` | Interrupted before the check answered: `130` for Ctrl-C, `143` for SIGTERM |
288
+
289
+ Only `clean` exits `0`: a status this CLI does not know exits `2`, so a newer
290
+ service can never pass a check by accident, and stderr names the status. An
291
+ interrupted check prints no report. Interrupted before it was sent, nothing
292
+ reached the service; after, a service that received it keeps running it, and
293
+ running the same check again picks up its result.
214
294
 
215
295
  An inconclusive check fails the check only when it concerns a file the
216
296
  change writes. One about other files is listed on an `Inconclusive outside
@@ -239,13 +319,12 @@ again picks up the same analysis.
239
319
  Service failures print the closed contract exactly: message, remedy, and any
240
320
  install URL. The codes, messages, and remedies are defined by the service in
241
321
  `server/src/check.rs` of `BrokkAi/bifrost-service`; the CLI does not
242
- rewrite them. The remedies name no client, so when one says to sign in the CLI
243
- adds the `slopcop login` command after it. A failed request prints no report
244
- on stdout.
245
-
246
- While SlopCop is still indexing the repository, the service answers
247
- `indexing_in_progress` at once instead of running the check. The CLI prints it
248
- and exits `2` without waiting or retrying.
322
+ rewrite them. The remedies name no client, so the CLI adds its own command
323
+ after some: `slopcop login` when the remedy is to sign in, the listing to
324
+ choose from after `workspace_not_found` or `workspace_repository_not_found`,
325
+ 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
327
+ report on stdout.
249
328
 
250
329
  ## API
251
330
 
@@ -268,11 +347,35 @@ were marked `new`, the CLI treats every finding as new, as that service gated
268
347
  on all of them. Non-2xx responses carry `code`, `message`,
269
348
  `remedy`, `retryable`, and an optional `installUrl`.
270
349
 
350
+ Each finding in the response carries an `id`; a service from before findings
351
+ could be ignored omits it.
352
+
353
+ `slopcop ignore <id>` calls `POST <service>/v1/ignore` with the same bearer
354
+ token and `{"findingId": "<id>"}`, and gets back
355
+ `{"findingId": "<id>", "status": "ignored"}`. Failures use the same closed
356
+ contract, including `finding_not_found`.
357
+
358
+ The account commands use the same bearer token. `GET <service>/v1/whoami`
359
+ answers `account`, `workspace` (`id`, `name`, `kind`, `role`, `current`),
360
+ `plan` (`pro` or `free`) and `workspaces`. `POST <service>/v1/workspace` with
361
+ `{"workspaceId"}` rebinds the login. `GET <service>/v1/repositories` answers
362
+ `repositories` (`id`, `provider`, `fullName`, `enabled`, `active`) with
363
+ `activeRepositoryLimit`, `activeRepositories` and `canManageRepositories`, and
364
+ `POST <service>/v1/repositories/state` with `{"repositoryId", "enabled"}`
365
+ answers `{repositoryId, fullName, enabled, active}`. Their failure codes add
366
+ `account_required`, `workspace_not_found`, `workspace_repository_not_found`,
367
+ `owner_required` and `browser_required` (a private Bitbucket or GitLab
368
+ repository, which only the web app can change) to the check's.
369
+
271
370
  `slopcop login` uses the device flow: `POST /api/device` returns a
272
371
  `deviceCode`, `userCode`, `verificationUri`, `expiresIn`, and `interval`, and
273
372
  `POST /api/token` returns `202` while pending or `200` with a `token` once
274
- approved. The polling codes are `authorization_pending`, `slow_down`,
275
- `expired_token`, and `access_denied`.
373
+ approved. The failure codes are `slow_down`, which raises the polling interval,
374
+ `expired_token`, `access_denied`, and `device_flow_disabled`. A failure the
375
+ service marks `retryable`, such as `rate_limited` or `service_unavailable`,
376
+ keeps the code valid, and so do a dropped connection and a proxy's `429`,
377
+ `502`, `503` or `504` without a code: login waits the `Retry-After`, or the
378
+ interval if that is longer, and polls again until the code expires.
276
379
 
277
380
  ## Development
278
381
 
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.4",
3
+ "version": "0.0.6",
4
4
  "description": "Static analysis for coding agents and CI: check a change through the hosted SlopCop API",
5
5
  "keywords": [
6
6
  "agents",