devin-qa-pack 0.1.0__tar.gz
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.
- devin_qa_pack-0.1.0/LICENSE +21 -0
- devin_qa_pack-0.1.0/PKG-INFO +330 -0
- devin_qa_pack-0.1.0/README.md +316 -0
- devin_qa_pack-0.1.0/pyproject.toml +27 -0
- devin_qa_pack-0.1.0/setup.cfg +4 -0
- devin_qa_pack-0.1.0/src/devin_qa_pack/__init__.py +1 -0
- devin_qa_pack-0.1.0/src/devin_qa_pack/adapters/__init__.py +17 -0
- devin_qa_pack-0.1.0/src/devin_qa_pack/adapters/aider.py +91 -0
- devin_qa_pack-0.1.0/src/devin_qa_pack/adapters/base.py +26 -0
- devin_qa_pack-0.1.0/src/devin_qa_pack/adapters/claude_code.py +131 -0
- devin_qa_pack-0.1.0/src/devin_qa_pack/adapters/devin.py +28 -0
- devin_qa_pack-0.1.0/src/devin_qa_pack/claims.py +226 -0
- devin_qa_pack-0.1.0/src/devin_qa_pack/cli.py +354 -0
- devin_qa_pack-0.1.0/src/devin_qa_pack/html_report.py +193 -0
- devin_qa_pack-0.1.0/src/devin_qa_pack/intent.py +588 -0
- devin_qa_pack-0.1.0/src/devin_qa_pack/paths.py +46 -0
- devin_qa_pack-0.1.0/src/devin_qa_pack/report.py +171 -0
- devin_qa_pack-0.1.0/src/devin_qa_pack/session_end.py +262 -0
- devin_qa_pack-0.1.0/src/devin_qa_pack/verify.py +446 -0
- devin_qa_pack-0.1.0/src/devin_qa_pack.egg-info/PKG-INFO +330 -0
- devin_qa_pack-0.1.0/src/devin_qa_pack.egg-info/SOURCES.txt +34 -0
- devin_qa_pack-0.1.0/src/devin_qa_pack.egg-info/dependency_links.txt +1 -0
- devin_qa_pack-0.1.0/src/devin_qa_pack.egg-info/entry_points.txt +2 -0
- devin_qa_pack-0.1.0/src/devin_qa_pack.egg-info/requires.txt +4 -0
- devin_qa_pack-0.1.0/src/devin_qa_pack.egg-info/top_level.txt +1 -0
- devin_qa_pack-0.1.0/tests/test_adapters.py +178 -0
- devin_qa_pack-0.1.0/tests/test_claims.py +128 -0
- devin_qa_pack-0.1.0/tests/test_cli.py +126 -0
- devin_qa_pack-0.1.0/tests/test_html_report.py +57 -0
- devin_qa_pack-0.1.0/tests/test_intent.py +376 -0
- devin_qa_pack-0.1.0/tests/test_offline_core.py +69 -0
- devin_qa_pack-0.1.0/tests/test_paths.py +23 -0
- devin_qa_pack-0.1.0/tests/test_report.py +93 -0
- devin_qa_pack-0.1.0/tests/test_session_end.py +195 -0
- devin_qa_pack-0.1.0/tests/test_smoke.py +4 -0
- devin_qa_pack-0.1.0/tests/test_verify.py +265 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Icaro0310
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: devin-qa-pack
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: QA audit for Devin sessions: verifies deliverable claims (tests, commits, files, pushes) against tool_call_state ground truth.
|
|
5
|
+
Author: Icaro0310
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.10
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: devin-internals-spec<0.4.0,>=0.3.0
|
|
11
|
+
Provides-Extra: dev
|
|
12
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
13
|
+
Dynamic: license-file
|
|
14
|
+
|
|
15
|
+
<div align="center">
|
|
16
|
+
|
|
17
|
+
<img src="assets/banner.svg" alt="devin-qa-pack" width="100%"/>
|
|
18
|
+
|
|
19
|
+
<a href="https://github.com/Icaro0310/devin-qa-pack/actions/workflows/ci.yml"><img src="https://github.com/Icaro0310/devin-qa-pack/actions/workflows/ci.yml/badge.svg" alt="CI"/></a>
|
|
20
|
+
<a href="https://github.com/Icaro0310/devin-qa-pack/releases"><img src="https://img.shields.io/github/v/release/Icaro0310/devin-qa-pack" alt="GitHub release"/></a>
|
|
21
|
+
<a href="https://scorecard.dev/viewer/?uri=github.com/Icaro0310/devin-qa-pack"><img src="https://api.scorecard.dev/projects/github.com/Icaro0310/devin-qa-pack/badge" alt="OpenSSF Scorecard"/></a>
|
|
22
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green" alt="License: MIT"/></a>
|
|
23
|
+
<img src="https://img.shields.io/badge/python-3.10%2B-blue" alt="Python 3.10+"/>
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
# devin-qa-pack
|
|
29
|
+
|
|
30
|
+
> **Unofficial community project.** Not affiliated with, endorsed by, or
|
|
31
|
+
> sponsored by Cognition AI. "Devin" is a trademark of Cognition AI.
|
|
32
|
+
|
|
33
|
+
**[Linux](README.linux.md)** · **[Personal Windows](README.windows.md)** · **[Corporate Windows](README.corporate-windows.md)**
|
|
34
|
+
|
|
35
|
+
Part of the [awesome-devin](https://github.com/Icaro0310/awesome-devin) ecosystem: the curated hub for the devin-* tools.
|
|
36
|
+
|
|
37
|
+
Flagship QA audit for Devin sessions: checks that what a session *claims* it
|
|
38
|
+
delivered is backed by what its tool calls *actually did* — tests run,
|
|
39
|
+
commits created, files written, work pushed, HTTP statuses returned —
|
|
40
|
+
and prints a verdict per session: `PASS` / `PARTIAL` / `UNVERIFIED`.
|
|
41
|
+
|
|
42
|
+
## The problem
|
|
43
|
+
|
|
44
|
+
Devin sessions end with the agent saying "tests passed", "committed
|
|
45
|
+
`a1b2c3d`", "pushed to origin". Those are text claims — a model can write
|
|
46
|
+
them whether or not the actions happened. Verifying them today means
|
|
47
|
+
scrolling the transcript by hand or trusting the summary. Teams that
|
|
48
|
+
adopt agent workflows need a cheap, repeatable way to answer *did this
|
|
49
|
+
session actually do what it claims?*
|
|
50
|
+
|
|
51
|
+
## Prior art
|
|
52
|
+
|
|
53
|
+
Transcript/session viewers (including Devin's own UI) show *what
|
|
54
|
+
happened*; CI status checks verify outcomes after the fact; neither
|
|
55
|
+
cross-checks the agent's delivery claims against recorded actions. The
|
|
56
|
+
general idea — compare declared intent with observed behavior — is old
|
|
57
|
+
(manifest-vs-manifest audits, `git fsck`, attestations like SLSA
|
|
58
|
+
provenance). What didn't exist: applying it to an agent's claims vs. its
|
|
59
|
+
own persisted tool-call log.
|
|
60
|
+
|
|
61
|
+
## What makes it Devin-native
|
|
62
|
+
|
|
63
|
+
Devin persists every tool call in `sessions.db → tool_call_state`. This
|
|
64
|
+
tool reads that table via
|
|
65
|
+
[devin-internals-spec](https://github.com/Icaro0310/devin-internals-spec)
|
|
66
|
+
and treats it as **ground truth**: a "tests passed" claim must be backed
|
|
67
|
+
by a run/execute call that ran a test runner and completed; "committed
|
|
68
|
+
`sha`" must show the hash in a call or in `git log`. Text-only auditors
|
|
69
|
+
*cannot* do this — remove Devin's store and the check disappears.
|
|
70
|
+
|
|
71
|
+
## Install
|
|
72
|
+
|
|
73
|
+
Python ≥ 3.10 and `pipx` are required. **Windows (PowerShell):** install `pipx` with `py -m pip install --user pipx`, run `py -m pipx ensurepath`, then reopen the terminal. **Linux (Debian/Ubuntu):** run `sudo apt install pipx python3-venv` and `pipx ensurepath`; reopen the terminal. Other Linux distributions should install `pipx` using their package manager.
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# one-liner installer (pipx preferred, pip --user fallback)
|
|
77
|
+
curl -fsSL https://raw.githubusercontent.com/Icaro0310/devin-qa-pack/main/install.sh | sh
|
|
78
|
+
|
|
79
|
+
# or directly
|
|
80
|
+
pipx install "devin-qa-pack @ git+https://github.com/Icaro0310/devin-qa-pack.git"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
[GitHub Releases](https://github.com/Icaro0310/devin-qa-pack/releases)
|
|
84
|
+
ship the wheel, sdist and CycloneDX SBOM per tag.
|
|
85
|
+
|
|
86
|
+
## Usage
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# audit one session (exact id or unique prefix)
|
|
90
|
+
devin-qa-pack audit --session <id> --sessions-db path/to/sessions.db
|
|
91
|
+
|
|
92
|
+
# audit everything, most recent first
|
|
93
|
+
devin-qa-pack audit --all --limit 20 --json
|
|
94
|
+
|
|
95
|
+
# aggregated report: one self-contained static HTML file (inline CSS,
|
|
96
|
+
# no JS, no external assets — opens offline)
|
|
97
|
+
devin-qa-pack report --sessions-db path/to/sessions.db --out report.html
|
|
98
|
+
|
|
99
|
+
# live audit at SessionEnd: audit ONLY the session that just ended
|
|
100
|
+
# (hook mode — writes a JSON side file, never touches the session)
|
|
101
|
+
devin-qa-pack session-end
|
|
102
|
+
|
|
103
|
+
# intent vs. coverage (QA-4): did the agent touch what the prompt named?
|
|
104
|
+
devin-qa-pack intent <session> --sessions-db path/to/sessions.db
|
|
105
|
+
|
|
106
|
+
# audit a foreign transcript instead of sessions.db (experimental)
|
|
107
|
+
devin-qa-pack audit --transcript .aider.chat.history.md
|
|
108
|
+
devin-qa-pack audit --transcript ~/.claude/projects/<slug>/<id>.jsonl
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Real output, on the synthetic fixture from the quick start:
|
|
112
|
+
|
|
113
|
+
```text
|
|
114
|
+
UNVERIFIED sess-unverifiable Mystery session — 1 claim(s): 0 verified, 0 disputed, 1 unverifiable
|
|
115
|
+
[unverifiable] file/docs/spec.pdf: no matching tool call and working dir not on disk
|
|
116
|
+
PARTIAL sess-disputed Disputed session — 2 claim(s): 0 verified, 2 disputed, 0 unverifiable
|
|
117
|
+
[disputed ] tests/tests: no execute call matching `tests` recorded
|
|
118
|
+
[disputed ] commit/deadbee: no commit call recorded and no repo on disk to check
|
|
119
|
+
PASS sess-verified Verified session — 4 claim(s): 4 verified, 0 disputed, 0 unverifiable
|
|
120
|
+
[verified ] tests/pytest: `python -m pytest -q` completed (tc-pytest)
|
|
121
|
+
[verified ] commit/a1b2c3d: `git commit -m fix` completed (tc-commit)
|
|
122
|
+
[verified ] push/push: `git push origin main` completed (tc-push)
|
|
123
|
+
[verified ] file/src/report.html: tool call tc-write completed
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Recorded as an asciicast: [assets/demo.cast](assets/demo.cast) —
|
|
127
|
+
`asciinema play demo.cast`.
|
|
128
|
+
|
|
129
|
+
The `report` subcommand audits all sessions (or one with `--session`,
|
|
130
|
+
bounded with `--limit`) and writes a single deterministic HTML file:
|
|
131
|
+
verdict counts, a per-session table and a per-claim breakdown with
|
|
132
|
+
evidence and the source excerpt for every checked claim.
|
|
133
|
+
|
|
134
|
+
`--sessions-db` may be omitted. It auto-detects
|
|
135
|
+
`%APPDATA%/devin/cli/sessions.db` on Windows and
|
|
136
|
+
`$XDG_DATA_HOME/devin/cli/sessions.db` on Linux (default
|
|
137
|
+
`~/.local/share/devin/cli/sessions.db`). Always read-only.
|
|
138
|
+
|
|
139
|
+
No Devin installed? Try it on a synthetic fixture:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
pipx install "devin-internals-spec==0.3.0"
|
|
143
|
+
devin-inspect make-fixture /tmp/fx
|
|
144
|
+
devin-qa-pack audit --all --sessions-db /tmp/fx/cli/sessions.db
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Exit codes: `0` every session `PASS` · `1` some session
|
|
148
|
+
`PARTIAL`/`UNVERIFIED` · `2` audit could not run.
|
|
149
|
+
|
|
150
|
+
## Intent vs. coverage (`intent`, QA-4)
|
|
151
|
+
|
|
152
|
+
`devin-qa-pack intent <session>` answers a different question: did the
|
|
153
|
+
agent actually touch what the user asked for? It takes the session's
|
|
154
|
+
**first user message**, extracts the paths/modules/repo names it
|
|
155
|
+
references, extracts every path seen in `tool_call_state` payloads
|
|
156
|
+
(writes, reads and commands all count as "touched") and reports two
|
|
157
|
+
heuristic findings:
|
|
158
|
+
|
|
159
|
+
- **`possibly_missed`** — paths the prompt explicitly named (filename
|
|
160
|
+
with an extension, absolute or `./`-prefixed path) that no tool call
|
|
161
|
+
ever referenced.
|
|
162
|
+
- **`scope_drift`** — touched paths sharing no directory, filename or
|
|
163
|
+
repo anchor with anything the prompt named.
|
|
164
|
+
|
|
165
|
+
Statuses: `aligned` (nothing flagged) · `flagged` (at least one missed
|
|
166
|
+
or drift path) · `skipped` (not computable — no user message, no
|
|
167
|
+
path-ish references in the prompt, or no tool calls). Exit codes:
|
|
168
|
+
`0` aligned · `1` flagged or skipped · `2` could not run. The same
|
|
169
|
+
analysis rides along as an `intent` field in the `session-end` side
|
|
170
|
+
file whenever the session resolves.
|
|
171
|
+
|
|
172
|
+
**This is a heuristic** — kept deliberately conservative: only
|
|
173
|
+
file-grade references can be "missed" (a bare `src/` mention or a
|
|
174
|
+
slash-word like `and/or` never is); coverage is by path-segment and
|
|
175
|
+
basename match, not semantics; and drift means *"no prompt-named
|
|
176
|
+
anchor"*, not *"wrong file"*. A prompt naming no paths at all yields
|
|
177
|
+
`skipped` rather than flagging every touched file.
|
|
178
|
+
|
|
179
|
+
## SessionEnd hook (live audit)
|
|
180
|
+
|
|
181
|
+
`devin-qa-pack session-end` audits **only the session that just ended**
|
|
182
|
+
and writes the verdict to a JSON **side file** — never into the
|
|
183
|
+
transcript or any Devin store. Session resolution order:
|
|
184
|
+
|
|
185
|
+
1. `--session-id <id>` (exact id or unique prefix)
|
|
186
|
+
2. the `session_id` field of the hook payload JSON on stdin
|
|
187
|
+
3. the `DEVIN_SESSION_ID` env var (exported by the hook dispatcher)
|
|
188
|
+
4. the most recently active session in `sessions.db`
|
|
189
|
+
|
|
190
|
+
The side file defaults to `<data-dir>/qa/<session-id>.json` (same
|
|
191
|
+
platform data dir as the store auto-detection; `--data-dir` and `--out`
|
|
192
|
+
override) and contains `{session_id, verdict, claims: [...],
|
|
193
|
+
audited_at}` — the same claim shape as `audit --json`, plus an
|
|
194
|
+
optional `intent` field (the QA-4 prompt-vs-touched-paths analysis)
|
|
195
|
+
when the session resolves. A one-line
|
|
196
|
+
summary is also printed. `--limit N` bounds the number of claims
|
|
197
|
+
verified.
|
|
198
|
+
|
|
199
|
+
**Fail-soft:** `session-end` always exits `0` once it ran — the verdict
|
|
200
|
+
travels in the side file, so a hook can never fail the host session. A
|
|
201
|
+
session that cannot be resolved produces a `SKIPPED` verdict (still
|
|
202
|
+
written to the side file when an id is known). Non-zero exits are
|
|
203
|
+
reserved for usage errors (`2`), consistent with the other subcommands.
|
|
204
|
+
|
|
205
|
+
Register it as a `SessionEnd` hook (hooks.json entry for the
|
|
206
|
+
`devin-powerups` hook dispatcher — it pipes the hook payload JSON on
|
|
207
|
+
stdin and exports `DEVIN_SESSION_ID`):
|
|
208
|
+
|
|
209
|
+
```json
|
|
210
|
+
{
|
|
211
|
+
"SessionEnd": [
|
|
212
|
+
{
|
|
213
|
+
"matcher": "",
|
|
214
|
+
"hooks": [
|
|
215
|
+
{
|
|
216
|
+
"type": "command",
|
|
217
|
+
"command": "devin-qa-pack session-end",
|
|
218
|
+
"timeout": 30
|
|
219
|
+
}
|
|
220
|
+
]
|
|
221
|
+
}
|
|
222
|
+
]
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Auditing other agents (experimental)
|
|
227
|
+
|
|
228
|
+
`audit --transcript` runs the same claim/evidence model over non-Devin
|
|
229
|
+
transcripts via the adapters in `src/devin_qa_pack/adapters/`:
|
|
230
|
+
|
|
231
|
+
- **`aider`** — `.aider.chat.history.md`. `> /run` and `> /test` records
|
|
232
|
+
become execute calls with `unknown` status (the history does not store
|
|
233
|
+
exit codes), so test claims resolve `unverifiable`; commit claims are
|
|
234
|
+
checked against `git log` in the working directory.
|
|
235
|
+
- **`claude-code`** — session `.jsonl` transcripts. `Bash` → execute,
|
|
236
|
+
`Write`/`Edit`/`MultiEdit`/`NotebookEdit` → write, `tool_result`
|
|
237
|
+
blocks mark calls completed/failed.
|
|
238
|
+
|
|
239
|
+
`--format` overrides extension-based detection; `--cwd` sets the
|
|
240
|
+
directory used for git/file checks. These adapters are experimental —
|
|
241
|
+
formats outside the recorded subsets degrade to `UNVERIFIED`, never to
|
|
242
|
+
a false `PASS`.
|
|
243
|
+
|
|
244
|
+
## Works with Devin alone (Devin-only mode)
|
|
245
|
+
|
|
246
|
+
devin-qa-pack is an offline, read-only audit of recorded Devin sessions. It
|
|
247
|
+
never calls an LLM, never touches the network, and never writes to Devin's
|
|
248
|
+
stores — a safe pick for restricted machines.
|
|
249
|
+
|
|
250
|
+
## Platform support
|
|
251
|
+
|
|
252
|
+
Tested on **Windows and Linux** (`windows-latest` + `ubuntu-latest` in CI).
|
|
253
|
+
The CLI session DB is auto-detected from `%APPDATA%/devin/cli/sessions.db`
|
|
254
|
+
on Windows and `$XDG_DATA_HOME/devin/cli/sessions.db` on Linux (default
|
|
255
|
+
`~/.local/share/devin/cli/sessions.db`). A legacy `~/.config/devin` layout is
|
|
256
|
+
also checked. macOS uses `~/Library/Application Support/devin/`. Pass
|
|
257
|
+
`--sessions-db` to override.
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
`--online` (QA-2, opt-in) enables live HEAD checks of deploy/URL claims
|
|
261
|
+
("deployed to https://…"), and only against `--allow-domain` hosts —
|
|
262
|
+
network is off by default and the audit is fully offline otherwise.
|
|
263
|
+
|
|
264
|
+
## Limitations
|
|
265
|
+
|
|
266
|
+
- `chat_message` and `tool_call_*_json` payloads are **unstable** formats
|
|
267
|
+
(see devin-internals-spec SCHEMA.md). Decoding is defensive; rows that
|
|
268
|
+
can't be read resolve claims to `unverifiable`, never to `disputed`.
|
|
269
|
+
- Claim extraction is heuristic: it looks for delivery phrasing
|
|
270
|
+
("tests passed", "committed <sha>", "created <path>", "pushed",
|
|
271
|
+
"the API returned 200"). Claims phrased differently are not
|
|
272
|
+
extracted — the audit then reports `UNVERIFIED`, not a false `PASS`.
|
|
273
|
+
- HTTP-status claims are checked only against recorded tool-call
|
|
274
|
+
output: a claim is `verified` when a recorded status matches,
|
|
275
|
+
`disputed` when outputs record a different status and `unverifiable`
|
|
276
|
+
when no output records any status. No request is ever replayed.
|
|
277
|
+
- File/commit checks use `sessions.working_directory` only when it
|
|
278
|
+
exists on disk and is a git repo — otherwise they rely on tool-call
|
|
279
|
+
evidence alone.
|
|
280
|
+
- The `intent` analysis is explicitly heuristic: prompt path extraction
|
|
281
|
+
is regex-based (bare directory mentions without extensions and
|
|
282
|
+
extensionless `a/b` tokens can be missed as references), "touched"
|
|
283
|
+
includes reads and commands not just writes, and later user
|
|
284
|
+
follow-ups are ignored — only the first user message sets intent.
|
|
285
|
+
Treat `possibly_missed`/`scope_drift` as review hints, not verdicts.
|
|
286
|
+
- The transcript adapters cover a subset of Aider/Claude Code formats:
|
|
287
|
+
aider's history cannot prove a `/run` succeeded (no exit codes), and
|
|
288
|
+
unrecognized tool names become `other` — still searchable evidence,
|
|
289
|
+
but weak. Real-world transcripts that differ degrade to
|
|
290
|
+
`UNVERIFIED`.
|
|
291
|
+
- It verifies *that* actions happened, not that the work is good.
|
|
292
|
+
Green tests in a tool call don't prove the fix is correct.
|
|
293
|
+
- Read-only, offline; no real-time monitoring, no MCP server (M2).
|
|
294
|
+
|
|
295
|
+
## Development
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
pip install -e ".[dev]"
|
|
299
|
+
python -m pytest
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
## When to use this
|
|
303
|
+
|
|
304
|
+
- You want to verify that a finished Devin session actually ran tests, created commits, wrote files, or pushed — not just claimed to.
|
|
305
|
+
- You are gating agent output in CI and need a machine-readable verdict (`PASS`/`PARTIAL`/`UNVERIFIED`) with exit codes.
|
|
306
|
+
- You want to audit many sessions at once, offline, without sending transcripts to an LLM — and optionally publish a single static HTML report (`devin-qa-pack report`).
|
|
307
|
+
- You are on a restricted machine: the tool is read-only and never touches the network.
|
|
308
|
+
|
|
309
|
+
## When NOT to use this
|
|
310
|
+
|
|
311
|
+
- You need a review of code quality or correctness — it verifies that actions happened, not that the work is good.
|
|
312
|
+
- You need real-time monitoring or an MCP server (on the M2 roadmap).
|
|
313
|
+
- Your agent is not Devin — the ground truth comes from Devin's `sessions.db`.
|
|
314
|
+
|
|
315
|
+
## FAQ
|
|
316
|
+
|
|
317
|
+
**How do I verify a Devin session actually ran the tests it claims?** Run `devin-qa-pack audit --session <id>`. It reads the session's `tool_call_state` rows from `sessions.db`, extracts delivery claims like "tests passed", and checks each against recorded tool calls — a claim without matching evidence resolves to `UNVERIFIED` or `PARTIAL`, not `PASS`.
|
|
318
|
+
|
|
319
|
+
**Does devin-qa-pack need network access or an API key?** No. It is a fully offline, read-only audit of the local `sessions.db`. It never calls an LLM, never sends data anywhere, and never writes to Devin's stores.
|
|
320
|
+
|
|
321
|
+
**Where does devin-qa-pack find sessions.db?** It auto-detects `%APPDATA%/devin/cli/sessions.db` on Windows, `$XDG_DATA_HOME/devin/cli/sessions.db` on Linux (`~/.local/share/devin/cli/sessions.db` by default), `~/Library/Application Support/devin/` on macOS, plus a legacy `~/.config/devin` layout. Override with `--sessions-db`.
|
|
322
|
+
|
|
323
|
+
## License
|
|
324
|
+
|
|
325
|
+
MIT — see [LICENSE](LICENSE).
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
If this saved you debugging time, a ⭐ on the repo helps others find it.
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<img src="assets/banner.svg" alt="devin-qa-pack" width="100%"/>
|
|
4
|
+
|
|
5
|
+
<a href="https://github.com/Icaro0310/devin-qa-pack/actions/workflows/ci.yml"><img src="https://github.com/Icaro0310/devin-qa-pack/actions/workflows/ci.yml/badge.svg" alt="CI"/></a>
|
|
6
|
+
<a href="https://github.com/Icaro0310/devin-qa-pack/releases"><img src="https://img.shields.io/github/v/release/Icaro0310/devin-qa-pack" alt="GitHub release"/></a>
|
|
7
|
+
<a href="https://scorecard.dev/viewer/?uri=github.com/Icaro0310/devin-qa-pack"><img src="https://api.scorecard.dev/projects/github.com/Icaro0310/devin-qa-pack/badge" alt="OpenSSF Scorecard"/></a>
|
|
8
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green" alt="License: MIT"/></a>
|
|
9
|
+
<img src="https://img.shields.io/badge/python-3.10%2B-blue" alt="Python 3.10+"/>
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
# devin-qa-pack
|
|
15
|
+
|
|
16
|
+
> **Unofficial community project.** Not affiliated with, endorsed by, or
|
|
17
|
+
> sponsored by Cognition AI. "Devin" is a trademark of Cognition AI.
|
|
18
|
+
|
|
19
|
+
**[Linux](README.linux.md)** · **[Personal Windows](README.windows.md)** · **[Corporate Windows](README.corporate-windows.md)**
|
|
20
|
+
|
|
21
|
+
Part of the [awesome-devin](https://github.com/Icaro0310/awesome-devin) ecosystem: the curated hub for the devin-* tools.
|
|
22
|
+
|
|
23
|
+
Flagship QA audit for Devin sessions: checks that what a session *claims* it
|
|
24
|
+
delivered is backed by what its tool calls *actually did* — tests run,
|
|
25
|
+
commits created, files written, work pushed, HTTP statuses returned —
|
|
26
|
+
and prints a verdict per session: `PASS` / `PARTIAL` / `UNVERIFIED`.
|
|
27
|
+
|
|
28
|
+
## The problem
|
|
29
|
+
|
|
30
|
+
Devin sessions end with the agent saying "tests passed", "committed
|
|
31
|
+
`a1b2c3d`", "pushed to origin". Those are text claims — a model can write
|
|
32
|
+
them whether or not the actions happened. Verifying them today means
|
|
33
|
+
scrolling the transcript by hand or trusting the summary. Teams that
|
|
34
|
+
adopt agent workflows need a cheap, repeatable way to answer *did this
|
|
35
|
+
session actually do what it claims?*
|
|
36
|
+
|
|
37
|
+
## Prior art
|
|
38
|
+
|
|
39
|
+
Transcript/session viewers (including Devin's own UI) show *what
|
|
40
|
+
happened*; CI status checks verify outcomes after the fact; neither
|
|
41
|
+
cross-checks the agent's delivery claims against recorded actions. The
|
|
42
|
+
general idea — compare declared intent with observed behavior — is old
|
|
43
|
+
(manifest-vs-manifest audits, `git fsck`, attestations like SLSA
|
|
44
|
+
provenance). What didn't exist: applying it to an agent's claims vs. its
|
|
45
|
+
own persisted tool-call log.
|
|
46
|
+
|
|
47
|
+
## What makes it Devin-native
|
|
48
|
+
|
|
49
|
+
Devin persists every tool call in `sessions.db → tool_call_state`. This
|
|
50
|
+
tool reads that table via
|
|
51
|
+
[devin-internals-spec](https://github.com/Icaro0310/devin-internals-spec)
|
|
52
|
+
and treats it as **ground truth**: a "tests passed" claim must be backed
|
|
53
|
+
by a run/execute call that ran a test runner and completed; "committed
|
|
54
|
+
`sha`" must show the hash in a call or in `git log`. Text-only auditors
|
|
55
|
+
*cannot* do this — remove Devin's store and the check disappears.
|
|
56
|
+
|
|
57
|
+
## Install
|
|
58
|
+
|
|
59
|
+
Python ≥ 3.10 and `pipx` are required. **Windows (PowerShell):** install `pipx` with `py -m pip install --user pipx`, run `py -m pipx ensurepath`, then reopen the terminal. **Linux (Debian/Ubuntu):** run `sudo apt install pipx python3-venv` and `pipx ensurepath`; reopen the terminal. Other Linux distributions should install `pipx` using their package manager.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# one-liner installer (pipx preferred, pip --user fallback)
|
|
63
|
+
curl -fsSL https://raw.githubusercontent.com/Icaro0310/devin-qa-pack/main/install.sh | sh
|
|
64
|
+
|
|
65
|
+
# or directly
|
|
66
|
+
pipx install "devin-qa-pack @ git+https://github.com/Icaro0310/devin-qa-pack.git"
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
[GitHub Releases](https://github.com/Icaro0310/devin-qa-pack/releases)
|
|
70
|
+
ship the wheel, sdist and CycloneDX SBOM per tag.
|
|
71
|
+
|
|
72
|
+
## Usage
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# audit one session (exact id or unique prefix)
|
|
76
|
+
devin-qa-pack audit --session <id> --sessions-db path/to/sessions.db
|
|
77
|
+
|
|
78
|
+
# audit everything, most recent first
|
|
79
|
+
devin-qa-pack audit --all --limit 20 --json
|
|
80
|
+
|
|
81
|
+
# aggregated report: one self-contained static HTML file (inline CSS,
|
|
82
|
+
# no JS, no external assets — opens offline)
|
|
83
|
+
devin-qa-pack report --sessions-db path/to/sessions.db --out report.html
|
|
84
|
+
|
|
85
|
+
# live audit at SessionEnd: audit ONLY the session that just ended
|
|
86
|
+
# (hook mode — writes a JSON side file, never touches the session)
|
|
87
|
+
devin-qa-pack session-end
|
|
88
|
+
|
|
89
|
+
# intent vs. coverage (QA-4): did the agent touch what the prompt named?
|
|
90
|
+
devin-qa-pack intent <session> --sessions-db path/to/sessions.db
|
|
91
|
+
|
|
92
|
+
# audit a foreign transcript instead of sessions.db (experimental)
|
|
93
|
+
devin-qa-pack audit --transcript .aider.chat.history.md
|
|
94
|
+
devin-qa-pack audit --transcript ~/.claude/projects/<slug>/<id>.jsonl
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Real output, on the synthetic fixture from the quick start:
|
|
98
|
+
|
|
99
|
+
```text
|
|
100
|
+
UNVERIFIED sess-unverifiable Mystery session — 1 claim(s): 0 verified, 0 disputed, 1 unverifiable
|
|
101
|
+
[unverifiable] file/docs/spec.pdf: no matching tool call and working dir not on disk
|
|
102
|
+
PARTIAL sess-disputed Disputed session — 2 claim(s): 0 verified, 2 disputed, 0 unverifiable
|
|
103
|
+
[disputed ] tests/tests: no execute call matching `tests` recorded
|
|
104
|
+
[disputed ] commit/deadbee: no commit call recorded and no repo on disk to check
|
|
105
|
+
PASS sess-verified Verified session — 4 claim(s): 4 verified, 0 disputed, 0 unverifiable
|
|
106
|
+
[verified ] tests/pytest: `python -m pytest -q` completed (tc-pytest)
|
|
107
|
+
[verified ] commit/a1b2c3d: `git commit -m fix` completed (tc-commit)
|
|
108
|
+
[verified ] push/push: `git push origin main` completed (tc-push)
|
|
109
|
+
[verified ] file/src/report.html: tool call tc-write completed
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Recorded as an asciicast: [assets/demo.cast](assets/demo.cast) —
|
|
113
|
+
`asciinema play demo.cast`.
|
|
114
|
+
|
|
115
|
+
The `report` subcommand audits all sessions (or one with `--session`,
|
|
116
|
+
bounded with `--limit`) and writes a single deterministic HTML file:
|
|
117
|
+
verdict counts, a per-session table and a per-claim breakdown with
|
|
118
|
+
evidence and the source excerpt for every checked claim.
|
|
119
|
+
|
|
120
|
+
`--sessions-db` may be omitted. It auto-detects
|
|
121
|
+
`%APPDATA%/devin/cli/sessions.db` on Windows and
|
|
122
|
+
`$XDG_DATA_HOME/devin/cli/sessions.db` on Linux (default
|
|
123
|
+
`~/.local/share/devin/cli/sessions.db`). Always read-only.
|
|
124
|
+
|
|
125
|
+
No Devin installed? Try it on a synthetic fixture:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
pipx install "devin-internals-spec==0.3.0"
|
|
129
|
+
devin-inspect make-fixture /tmp/fx
|
|
130
|
+
devin-qa-pack audit --all --sessions-db /tmp/fx/cli/sessions.db
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Exit codes: `0` every session `PASS` · `1` some session
|
|
134
|
+
`PARTIAL`/`UNVERIFIED` · `2` audit could not run.
|
|
135
|
+
|
|
136
|
+
## Intent vs. coverage (`intent`, QA-4)
|
|
137
|
+
|
|
138
|
+
`devin-qa-pack intent <session>` answers a different question: did the
|
|
139
|
+
agent actually touch what the user asked for? It takes the session's
|
|
140
|
+
**first user message**, extracts the paths/modules/repo names it
|
|
141
|
+
references, extracts every path seen in `tool_call_state` payloads
|
|
142
|
+
(writes, reads and commands all count as "touched") and reports two
|
|
143
|
+
heuristic findings:
|
|
144
|
+
|
|
145
|
+
- **`possibly_missed`** — paths the prompt explicitly named (filename
|
|
146
|
+
with an extension, absolute or `./`-prefixed path) that no tool call
|
|
147
|
+
ever referenced.
|
|
148
|
+
- **`scope_drift`** — touched paths sharing no directory, filename or
|
|
149
|
+
repo anchor with anything the prompt named.
|
|
150
|
+
|
|
151
|
+
Statuses: `aligned` (nothing flagged) · `flagged` (at least one missed
|
|
152
|
+
or drift path) · `skipped` (not computable — no user message, no
|
|
153
|
+
path-ish references in the prompt, or no tool calls). Exit codes:
|
|
154
|
+
`0` aligned · `1` flagged or skipped · `2` could not run. The same
|
|
155
|
+
analysis rides along as an `intent` field in the `session-end` side
|
|
156
|
+
file whenever the session resolves.
|
|
157
|
+
|
|
158
|
+
**This is a heuristic** — kept deliberately conservative: only
|
|
159
|
+
file-grade references can be "missed" (a bare `src/` mention or a
|
|
160
|
+
slash-word like `and/or` never is); coverage is by path-segment and
|
|
161
|
+
basename match, not semantics; and drift means *"no prompt-named
|
|
162
|
+
anchor"*, not *"wrong file"*. A prompt naming no paths at all yields
|
|
163
|
+
`skipped` rather than flagging every touched file.
|
|
164
|
+
|
|
165
|
+
## SessionEnd hook (live audit)
|
|
166
|
+
|
|
167
|
+
`devin-qa-pack session-end` audits **only the session that just ended**
|
|
168
|
+
and writes the verdict to a JSON **side file** — never into the
|
|
169
|
+
transcript or any Devin store. Session resolution order:
|
|
170
|
+
|
|
171
|
+
1. `--session-id <id>` (exact id or unique prefix)
|
|
172
|
+
2. the `session_id` field of the hook payload JSON on stdin
|
|
173
|
+
3. the `DEVIN_SESSION_ID` env var (exported by the hook dispatcher)
|
|
174
|
+
4. the most recently active session in `sessions.db`
|
|
175
|
+
|
|
176
|
+
The side file defaults to `<data-dir>/qa/<session-id>.json` (same
|
|
177
|
+
platform data dir as the store auto-detection; `--data-dir` and `--out`
|
|
178
|
+
override) and contains `{session_id, verdict, claims: [...],
|
|
179
|
+
audited_at}` — the same claim shape as `audit --json`, plus an
|
|
180
|
+
optional `intent` field (the QA-4 prompt-vs-touched-paths analysis)
|
|
181
|
+
when the session resolves. A one-line
|
|
182
|
+
summary is also printed. `--limit N` bounds the number of claims
|
|
183
|
+
verified.
|
|
184
|
+
|
|
185
|
+
**Fail-soft:** `session-end` always exits `0` once it ran — the verdict
|
|
186
|
+
travels in the side file, so a hook can never fail the host session. A
|
|
187
|
+
session that cannot be resolved produces a `SKIPPED` verdict (still
|
|
188
|
+
written to the side file when an id is known). Non-zero exits are
|
|
189
|
+
reserved for usage errors (`2`), consistent with the other subcommands.
|
|
190
|
+
|
|
191
|
+
Register it as a `SessionEnd` hook (hooks.json entry for the
|
|
192
|
+
`devin-powerups` hook dispatcher — it pipes the hook payload JSON on
|
|
193
|
+
stdin and exports `DEVIN_SESSION_ID`):
|
|
194
|
+
|
|
195
|
+
```json
|
|
196
|
+
{
|
|
197
|
+
"SessionEnd": [
|
|
198
|
+
{
|
|
199
|
+
"matcher": "",
|
|
200
|
+
"hooks": [
|
|
201
|
+
{
|
|
202
|
+
"type": "command",
|
|
203
|
+
"command": "devin-qa-pack session-end",
|
|
204
|
+
"timeout": 30
|
|
205
|
+
}
|
|
206
|
+
]
|
|
207
|
+
}
|
|
208
|
+
]
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Auditing other agents (experimental)
|
|
213
|
+
|
|
214
|
+
`audit --transcript` runs the same claim/evidence model over non-Devin
|
|
215
|
+
transcripts via the adapters in `src/devin_qa_pack/adapters/`:
|
|
216
|
+
|
|
217
|
+
- **`aider`** — `.aider.chat.history.md`. `> /run` and `> /test` records
|
|
218
|
+
become execute calls with `unknown` status (the history does not store
|
|
219
|
+
exit codes), so test claims resolve `unverifiable`; commit claims are
|
|
220
|
+
checked against `git log` in the working directory.
|
|
221
|
+
- **`claude-code`** — session `.jsonl` transcripts. `Bash` → execute,
|
|
222
|
+
`Write`/`Edit`/`MultiEdit`/`NotebookEdit` → write, `tool_result`
|
|
223
|
+
blocks mark calls completed/failed.
|
|
224
|
+
|
|
225
|
+
`--format` overrides extension-based detection; `--cwd` sets the
|
|
226
|
+
directory used for git/file checks. These adapters are experimental —
|
|
227
|
+
formats outside the recorded subsets degrade to `UNVERIFIED`, never to
|
|
228
|
+
a false `PASS`.
|
|
229
|
+
|
|
230
|
+
## Works with Devin alone (Devin-only mode)
|
|
231
|
+
|
|
232
|
+
devin-qa-pack is an offline, read-only audit of recorded Devin sessions. It
|
|
233
|
+
never calls an LLM, never touches the network, and never writes to Devin's
|
|
234
|
+
stores — a safe pick for restricted machines.
|
|
235
|
+
|
|
236
|
+
## Platform support
|
|
237
|
+
|
|
238
|
+
Tested on **Windows and Linux** (`windows-latest` + `ubuntu-latest` in CI).
|
|
239
|
+
The CLI session DB is auto-detected from `%APPDATA%/devin/cli/sessions.db`
|
|
240
|
+
on Windows and `$XDG_DATA_HOME/devin/cli/sessions.db` on Linux (default
|
|
241
|
+
`~/.local/share/devin/cli/sessions.db`). A legacy `~/.config/devin` layout is
|
|
242
|
+
also checked. macOS uses `~/Library/Application Support/devin/`. Pass
|
|
243
|
+
`--sessions-db` to override.
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
`--online` (QA-2, opt-in) enables live HEAD checks of deploy/URL claims
|
|
247
|
+
("deployed to https://…"), and only against `--allow-domain` hosts —
|
|
248
|
+
network is off by default and the audit is fully offline otherwise.
|
|
249
|
+
|
|
250
|
+
## Limitations
|
|
251
|
+
|
|
252
|
+
- `chat_message` and `tool_call_*_json` payloads are **unstable** formats
|
|
253
|
+
(see devin-internals-spec SCHEMA.md). Decoding is defensive; rows that
|
|
254
|
+
can't be read resolve claims to `unverifiable`, never to `disputed`.
|
|
255
|
+
- Claim extraction is heuristic: it looks for delivery phrasing
|
|
256
|
+
("tests passed", "committed <sha>", "created <path>", "pushed",
|
|
257
|
+
"the API returned 200"). Claims phrased differently are not
|
|
258
|
+
extracted — the audit then reports `UNVERIFIED`, not a false `PASS`.
|
|
259
|
+
- HTTP-status claims are checked only against recorded tool-call
|
|
260
|
+
output: a claim is `verified` when a recorded status matches,
|
|
261
|
+
`disputed` when outputs record a different status and `unverifiable`
|
|
262
|
+
when no output records any status. No request is ever replayed.
|
|
263
|
+
- File/commit checks use `sessions.working_directory` only when it
|
|
264
|
+
exists on disk and is a git repo — otherwise they rely on tool-call
|
|
265
|
+
evidence alone.
|
|
266
|
+
- The `intent` analysis is explicitly heuristic: prompt path extraction
|
|
267
|
+
is regex-based (bare directory mentions without extensions and
|
|
268
|
+
extensionless `a/b` tokens can be missed as references), "touched"
|
|
269
|
+
includes reads and commands not just writes, and later user
|
|
270
|
+
follow-ups are ignored — only the first user message sets intent.
|
|
271
|
+
Treat `possibly_missed`/`scope_drift` as review hints, not verdicts.
|
|
272
|
+
- The transcript adapters cover a subset of Aider/Claude Code formats:
|
|
273
|
+
aider's history cannot prove a `/run` succeeded (no exit codes), and
|
|
274
|
+
unrecognized tool names become `other` — still searchable evidence,
|
|
275
|
+
but weak. Real-world transcripts that differ degrade to
|
|
276
|
+
`UNVERIFIED`.
|
|
277
|
+
- It verifies *that* actions happened, not that the work is good.
|
|
278
|
+
Green tests in a tool call don't prove the fix is correct.
|
|
279
|
+
- Read-only, offline; no real-time monitoring, no MCP server (M2).
|
|
280
|
+
|
|
281
|
+
## Development
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
pip install -e ".[dev]"
|
|
285
|
+
python -m pytest
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## When to use this
|
|
289
|
+
|
|
290
|
+
- You want to verify that a finished Devin session actually ran tests, created commits, wrote files, or pushed — not just claimed to.
|
|
291
|
+
- You are gating agent output in CI and need a machine-readable verdict (`PASS`/`PARTIAL`/`UNVERIFIED`) with exit codes.
|
|
292
|
+
- You want to audit many sessions at once, offline, without sending transcripts to an LLM — and optionally publish a single static HTML report (`devin-qa-pack report`).
|
|
293
|
+
- You are on a restricted machine: the tool is read-only and never touches the network.
|
|
294
|
+
|
|
295
|
+
## When NOT to use this
|
|
296
|
+
|
|
297
|
+
- You need a review of code quality or correctness — it verifies that actions happened, not that the work is good.
|
|
298
|
+
- You need real-time monitoring or an MCP server (on the M2 roadmap).
|
|
299
|
+
- Your agent is not Devin — the ground truth comes from Devin's `sessions.db`.
|
|
300
|
+
|
|
301
|
+
## FAQ
|
|
302
|
+
|
|
303
|
+
**How do I verify a Devin session actually ran the tests it claims?** Run `devin-qa-pack audit --session <id>`. It reads the session's `tool_call_state` rows from `sessions.db`, extracts delivery claims like "tests passed", and checks each against recorded tool calls — a claim without matching evidence resolves to `UNVERIFIED` or `PARTIAL`, not `PASS`.
|
|
304
|
+
|
|
305
|
+
**Does devin-qa-pack need network access or an API key?** No. It is a fully offline, read-only audit of the local `sessions.db`. It never calls an LLM, never sends data anywhere, and never writes to Devin's stores.
|
|
306
|
+
|
|
307
|
+
**Where does devin-qa-pack find sessions.db?** It auto-detects `%APPDATA%/devin/cli/sessions.db` on Windows, `$XDG_DATA_HOME/devin/cli/sessions.db` on Linux (`~/.local/share/devin/cli/sessions.db` by default), `~/Library/Application Support/devin/` on macOS, plus a legacy `~/.config/devin` layout. Override with `--sessions-db`.
|
|
308
|
+
|
|
309
|
+
## License
|
|
310
|
+
|
|
311
|
+
MIT — see [LICENSE](LICENSE).
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
If this saved you debugging time, a ⭐ on the repo helps others find it.
|