@brokkai/slopcop 0.0.9 → 0.0.11

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
@@ -145,9 +145,22 @@ present, and names what it did:
145
145
  A skill that is already there is left alone by init, so running it again is
146
146
  safe. `slopcop login` and every check also install the skill in those
147
147
  directories, rewriting one that differs from the skill bundled into the binary,
148
- so an agent follows the instructions of the slopcop version it runs; local
149
- edits to an installed skill do not survive them. `slopcop init --no-skill`
150
- skips the install and any update of it.
148
+ so an agent follows the instructions of the slopcop version it runs. Each
149
+ install records the version that wrote it, and what each file held, in
150
+ `.slopcop-skill.json` in the skill folder. An update names the version it
151
+ replaces, the new one and the files that changed, for example:
152
+
153
+ ```
154
+ slopcop: updated the slopcop skill at ~/.claude/skills/slopcop from v0.0.9 to v0.0.10 (changed: SKILL.md). Reread it if you loaded the old one.
155
+ ```
156
+
157
+ It removes the files the new skill no longer has. A skill with local edits,
158
+ one that matches neither its record nor any release, is copied first to
159
+ `skill-backups/<harness>-<time>` next to the slopcop configuration, outside
160
+ every skills directory so no harness loads it as a second skill, and the
161
+ notice says where. A check's `json` and `sarif` reports carry the same update
162
+ (see below). `slopcop init --no-skill` skips the install and any update of
163
+ it.
151
164
 
152
165
  Init also adds a `Stop` hook for each harness installed here, and leaves
153
166
  everything else in the file as it was:
@@ -166,13 +179,28 @@ When the agent stops, the hook checks the working tree through the same
166
179
  hosted API, but only when all of these hold:
167
180
 
168
181
  - the session wrote files in the repository with its edit tools (a Codex
169
- session's subagents included);
182
+ session's subagents included), or the working tree has a changed
183
+ dependency manifest or lockfile (see below);
170
184
  - slopcop is signed in, and the workspace a check would use
171
185
  (`$SLOPCOP_WORKSPACE`, or the login's) has the repository active
172
186
  (`slopcop repo list`), so nothing is sent from other repositories;
173
187
  - the tree differs from the last check in the session, including a check the
174
188
  agent ran by hand.
175
189
 
190
+ An agent often adds a dependency through its shell, with `npm install`,
191
+ `pnpm add`, `cargo add` or `uv add`, which no edit tool records. So the hook
192
+ also checks when git shows one of these files changed, added or untracked in
193
+ any directory of the repository: `package.json`, `package-lock.json`,
194
+ `npm-shrinkwrap.json`, `pnpm-lock.yaml`, `yarn.lock`, `Cargo.toml`,
195
+ `Cargo.lock`, `pyproject.toml`, `uv.lock`, `poetry.lock`, `requirements*.txt`,
196
+ `go.mod` and `go.sum`. Files git ignores and those under `node_modules` do
197
+ not count. The hook recognises these files by name only: it never reads
198
+ them, runs a package manager or asks an advisory database; the hosted check
199
+ reads them like any other file in the change. A changed dependency file
200
+ counts as one the session wrote, since the hook cannot tell which command
201
+ changed it, so its new findings are handed to the agent like those in files
202
+ it edited, even if the file was already changed when the session began.
203
+
176
204
  New findings in files the session wrote are handed to the agent to fix, once
177
205
  for a given tree and at most twice in a row; then the agent is let go and you
178
206
  are told what remains. A finding ignored with `slopcop ignore` is not handed
@@ -197,8 +225,10 @@ slopcop login # browser device flow
197
225
  slopcop login --token "$SLOPCOP_TOKEN" # existing credential, for CI and agents
198
226
  ```
199
227
 
200
- The browser flow prints a URL and a code and stores the token once the login is
201
- approved. The service URL defaults to `https://slopcop.com`; `--service`,
228
+ The browser flow prints a link that opens the approval page with the code
229
+ filled in, plus the page and code to type in instead, and stores the token once
230
+ the login is approved. Approve only if the page shows the code your terminal
231
+ printed. The service URL defaults to `https://slopcop.com`; `--service`,
202
232
  `$SLOPCOP_SERVICE`, or a stored value override it.
203
233
 
204
234
  The credential lives in `slopcop/config.json` under the user config directory
@@ -248,29 +278,43 @@ add`: a first check adds a repository. When the workspace would then pay for
248
278
  it (it already has an active repository and is charged), the service refuses
249
279
  the check with `repository_add_unconfirmed` until a person confirms: at a
250
280
  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
255
- workspaces, members, credits and repository settings stay in the web app. The
256
- commands exit `0` on success and `2` with the service's message and remedy
257
- otherwise, as `ignore` does.
281
+ [y/N]`, and on a yes sends the check again and says `added owner/name to
282
+ "Workspace"` on stderr. With no terminal, as for an agent or CI (a pipe or the
283
+ null device is not one), nothing is asked: the check exits `4` with the
284
+ service's remedy, a line naming the command that confirms it, and, in `json`,
285
+ a `failed` report naming the code. A no at the terminal ends the same way.
286
+ Once the person has approved it, `check --add-repository --workspace
287
+ <name|id>` confirms without a terminal; the flag needs `--workspace` (the
288
+ flag itself, not `$SLOPCOP_WORKSPACE`), so an approval given for one
289
+ workspace cannot add the repository to the one the login happens to point at.
290
+ The flag changes nothing for a repository already in that workspace. A
291
+ workspace's first repository is added without asking. Deleting repositories,
292
+ archiving workspaces, members, credits and repository settings stay in the web
293
+ app. The commands exit `0` on success and `2` with the service's message and
294
+ remedy otherwise, as `ignore` does.
258
295
 
259
296
  ## Check
260
297
 
261
298
  ```console
262
299
  slopcop # check the change in the current checkout
263
300
  slopcop check --format json # same, machine-readable
264
- slopcop --root ../repo --base HEAD~1
301
+ slopcop --root ../repo --base origin/main
265
302
  ```
266
303
 
267
304
  The base commit defaults to the merge base with the branch upstream, then the
268
305
  merge base with `origin/HEAD`, then `HEAD` when neither is known. When the
269
306
  upstream merge base yields an empty patch, as on a branch whose commits are all
270
307
  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
272
- base commit in its clone; a missing one comes back as the service's
273
- `base_not_found` message and remedy.
308
+ right after a push still covers the branch. `--base REV` names the branch the
309
+ change started from and, like `git diff REV...HEAD`, uses the merge base of
310
+ `REV` and `HEAD`, so commits that landed on `REV` after the branch point are not
311
+ sent as reverse edits. `--base-exact REV` diffs against `REV` itself. The
312
+ service must already have the base commit in its clone; a missing one comes back as the service's
313
+ `base_not_found` message and remedy. The CLI then asks origin for its default
314
+ branch (`git ls-remote`, no prompt, 10 second limit) and adds a line when the
315
+ clone explains the failure: origin's default branch was renamed and
316
+ `origin/HEAD` still names the old one, or the base is not on origin's default
317
+ branch.
274
318
 
275
319
  Every run sends one check request, even when the working tree matches the base
276
320
  and the patch is empty. A clean result or a failure always comes from the
@@ -284,14 +328,16 @@ Flags:
284
328
  | Flag | Meaning |
285
329
  | --- | --- |
286
330
  | `--root PATH` | repository to check (default `.`) |
287
- | `--base REV` | base commit or revision for the change |
331
+ | `--base REV` | branch or revision the change started from; the base is its merge base with `HEAD` |
332
+ | `--base-exact REV` | exact base commit or revision, without a merge base |
288
333
  | `--format human\|json\|sarif` | report format (default `human`) |
289
334
  | `--fail-on never\|finding\|note\|warning\|error` | exit-1 threshold for new findings (default `finding`) |
290
335
  | `--policy PATH` | repository-relative `.rqlp` file to evaluate (repeatable) |
291
336
  | `--no-policy-discovery` | skip `.slopcop/policies` rules |
292
337
  | `--timeout DURATION` | how long to wait for the result (default `10m`) |
293
338
  | `-w`, `--workspace NAME\|ID` | check in, and bill, this workspace of the account instead of the login's |
294
- | `--verbose` | print the resolved request to stderr |
339
+ | `--add-repository` | add the repository to the workspace `--workspace` names, which then pays for it, without asking at a terminal; for after the user approved it |
340
+ | `--verbose` | print the resolved request to stderr, and name each inconclusive check in `human` |
295
341
 
296
342
  ### What is sent
297
343
 
@@ -368,8 +414,13 @@ summary line such as `1 new finding across 1 file(s); 72 already in the code |
368
414
  Analysis complete`, and any omitted new findings or
369
415
  incomplete checks. `json` prints `status`, `baseCommit`, `summary`
370
416
  (`newFindings` and `existingFindings` count the split), `findings` (each with
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`
417
+ `new` and its `id`), `incomplete`, `inconclusive`, `failure` when the analysis did not
418
+ complete, and `emptyChange` when the patch was empty. When the check
419
+ installed or updated the skill, `skillUpdated` lists each skill directory it
420
+ wrote: `dir`, `from` (a release, `unknown`, or absent for a fresh install),
421
+ `to`, `changed` and, for a skill with local edits, `backup`; the failed and
422
+ pending reports carry it too, and `sarif` puts it in
423
+ `properties["slopcop.skillUpdated"]`. `sarif` prints a SARIF 2.1.0 log whose results carry `baselineState`
373
424
  `new` and the finding id in `properties["slopcop.findingId"]`. `--format` only
374
425
  changes the rendering, never the request, so the service answers the same check
375
426
  whichever is used.
@@ -390,10 +441,18 @@ reached the service; after, a service that received it keeps running it, and
390
441
  running the same check again picks up its result.
391
442
 
392
443
  An inconclusive check, one that ran but could not prove there is nothing
393
- more to find, never changes the exit code and is not named in any format.
394
- Complete proof is rare in static analysis, typically at a library boundary,
395
- so this is the norm rather than a gap. `summary.inconclusive` counts them in
396
- `json`, as does `slopcop.inconclusive` in `sarif`. A check that timed out or
444
+ more to find, never changes the exit code or the status. Complete proof is
445
+ rare in static analysis, typically at a library boundary, so this is the norm
446
+ rather than a gap. Each report still says where they are, so a reviewer can
447
+ judge what a `clean` result is worth: `human` prints one `Inconclusive:` line
448
+ with the count and how many concern only files the change does not write, and
449
+ `--verbose` names each check. `json` lists them in `inconclusive`, each with
450
+ `policyId`, `reason` and `elsewhere` (true when it concerns only files the
451
+ change does not write), beside the `summary.inconclusive` count. `sarif` adds
452
+ a `note` notification per check with `slopcop.inconclusive` and
453
+ `slopcop.elsewhere` properties. The service names at most 50; the counts
454
+ cover the rest. It does not yet say which files or lines each one concerns,
455
+ or what evidence was missing. A check that timed out or
397
456
  that Bifrost judged unreliable is incomplete and counts wherever it is.
398
457
 
399
458
  The service applies `--fail-on` and sets the status; the exit code follows it.
@@ -420,9 +479,11 @@ rewrite them. The remedies name no client, so the CLI adds its own command
420
479
  after some: `slopcop login` when the remedy is to sign in, the listing to
421
480
  choose from after `workspace_not_found` or `workspace_repository_not_found`,
422
481
  and `slopcop whoami` after `repository_disabled`, since the workspace that
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`,
482
+ disabled it is the one this login is bound to, `--workspace` after
483
+ `owner_required`, and `--add-repository --workspace "Name"`, with the
484
+ workspace the check would have added the repository to, after
485
+ `repository_add_unconfirmed`. A failed check exits `4` when only a person can
486
+ clear the refusal (`auth_required`, `auth_expired`, `account_required`,
426
487
  `repo_not_indexed`, `app_not_installed`, `app_no_repo_access`,
427
488
  `gitlab_not_connected`, `no_access`, `insufficient_credits`,
428
489
  `repository_disabled`, `repository_add_unconfirmed`,
@@ -451,11 +512,11 @@ The CLI calls `POST <service>/v1/check` with a bearer token:
451
512
  }
452
513
  ```
453
514
 
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`,
515
+ `addRepository` is sent only after a person confirms adding the repository, at
516
+ the terminal or with `--add-repository`. The service rejects any other field.
517
+ With `--workspace`, every request, the check's, the ignore's and the account
518
+ routes', carries the workspace's id in the `SlopCop-Workspace` header; a name
519
+ is first looked up with `GET <service>/v1/whoami`. The response carries `status`,
459
520
  `baseCommit`, `applied`, `summary`, `findings`, `incomplete`, and `failure`
460
521
  when the analysis did not complete. Against a service from before findings
461
522
  were marked `new`, the CLI treats every finding as new, as that service gated
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.9",
3
+ "version": "0.0.11",
4
4
  "description": "Static analysis for coding agents and CI: check a change through the hosted SlopCop API",
5
5
  "keywords": [
6
6
  "agents",