You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* feat(gitlab): gl-mrs MR triage board + watch-mine supervisor
gl-mrs lists MRs (default author=@me), sorted failing-first, each enriched
in parallel with what you'd otherwise round-trip for: pipeline status
(a failure shows the failed job name = the failure class), approval state,
age, diff size, watch-state cross-reference, and conflict/draft/threads
flags. Actionable footer points at the first failing-and-unwatched MR.
"Mine" is just the default filter, not a special op — enumeration is a
platform concern, kept out of the generic watch preset.
watch-mine.sh: glue between a list-mine op and the watch preset — runs the
feed op, extracts ids, spawns one watcher each. Idempotent, safe on /loop.
gl-mrs:failed,iids | watch-mine turns "ping me when any of my MRs goes red"
into one looped command.
Enrich knobs (enrich_workers/enrich_cap/per_page) passed through as
SUPERTOOL_* env. 44 unit tests; full suite 3135 passed.
Refs #274 (gh-prs twin)
Co-Authored-By: Max <noreply>
* fix(gl-mrs): review fixes — iids None-guard, fd leak, _age skew, main() tests
Addresses PR #275 review:
- iids output guards against a missing iid (no stray "None" into the
watch-mine feed)
- _watched_iids closes the PID file via context manager (no fd leak)
- _age guards future timestamps (clock skew) → "now" instead of "-1d";
datetime import hoisted to module top
- +9 tests: _age skew/bad-iso, _flags True-suppression, and main()
integration (iids output, missing-iid skip, failed filter, glab error,
bad JSON) — covers the watch-mine.sh contract
53 gl-mrs tests pass.
Co-Authored-By: Max <noreply>
Copy file name to clipboardExpand all lines: .supertool.example.json
+9Lines changed: 9 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -274,6 +274,15 @@
274
274
"lines": 80,
275
275
"error_patterns": "ERROR,FAIL,Fatal"
276
276
},
277
+
"gl-mrs": {
278
+
"cmd": "python3 {path}gitlab/mrs.py {args}",
279
+
"timeout": 60,
280
+
"description": "MR triage board. Override the gitlab preset's defaults to tune pipeline enrichment — extra keys pass through as SUPERTOOL_ENRICH_WORKERS / SUPERTOOL_ENRICH_CAP / SUPERTOOL_PER_PAGE.",
281
+
"example": "gl-mrs:author=@me,failed",
282
+
"enrich_workers": 8,
283
+
"enrich_cap": 40,
284
+
"per_page": 50
285
+
},
277
286
"_hidden_internal": {
278
287
"cmd": "echo internal-helper",
279
288
"description": "Hidden from `./supertool ops` output via status:0 — useful for ops that exist for aliases or scripts but shouldn't clutter the public listing.",
Copy file name to clipboardExpand all lines: CHANGELOG.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
10
10
### Added
11
11
12
+
-**`gl-mrs` — MR triage board.** Lists MRs (default `author=@me`), sorted failing-first then stalest, each enriched in parallel with everything you'd otherwise round-trip for: pipeline status (a failure shows the failed **job name** — `phpstan2`, `test_unit_dpt` — i.e. the failure class, pre-empting a `gl-job` call), approval state, age, diff size, watch-state cross-reference (which MRs already have a live `watch` poller), and `conflict`/`draft`/`threads` flags. Footer points at the first failing-and-unwatched MR. Filters: `author`/`reviewer`/`assignee`/`label`/`milestone`/`state`/`per`. Flags: `nopipe`, `iids` (bare id list), `failed` (only failing). Tunable via `enrich_workers`/`enrich_cap`/`per_page`. "Mine" is just the default filter, not a special op — enumeration is a platform concern, kept out of the generic `watch` preset. See [docs/presets/gitlab.md](docs/presets/gitlab.md).
13
+
-**`presets/watch/watch-mine.sh` — watch-a-whole-query supervisor.** Glue between a "list mine" op (`gl-mrs`/`gh-prs`) and the `watch` preset: runs the feed op, extracts ids, spawns one watcher each. Idempotent, so it's safe on `/loop`. `gl-mrs:failed,iids | watch` turns "ping me when any of my MRs goes red" into one looped command. See [docs/presets/watch.md](docs/presets/watch.md).
12
14
-**`watch` preset — background event pollers with async wake into Claude Code.** New ops `watch:SOURCE:ID[:only=...]`, `unwatch:SOURCE:ID`, `watches`. Each invocation forks a detached poller that emits state-change events to a UDS socket, a status file, and macOS Notification Center. Source-plugin contract makes new sources ~50 lines. Bundled sources: `github-pr` (PR state, checks, reviews, comments, merge/close, conflicts) and `gitlab-mr` (MR state, pipeline, merge/close, conflicts). Closes [#165](https://github.com/Digital-Process-Tools/claude-supertool/issues/165). See [docs/presets/watch.md](docs/presets/watch.md).
13
15
-**`notifiers/claude-channel/` — MCP channel server for async wake.** TypeScript / Bun server that binds the watch UDS socket and pushes events into a running Claude Code session via the Channels feature (research preview, requires Claude Code v2.1.80+). Events arrive as `<channel source="claude-channel" watcher_source="<source>" id="<id>" event="<event>" ...>` tags. UDS file mode 0600 + localhost-only auth model. Launch with `claude --dangerously-load-development-channels server:claude-channel`. See [notifiers/claude-channel/README.md](notifiers/claude-channel/README.md).
14
16
-**`glob` brace expansion.**`glob:src/**/*.{json,xml}` now fans out into `*.json` + `*.xml` (shell/fd/ripgrep semantics) and dedupes results, instead of silently returning 0 files. Supports multiple groups (`{a,b}.{x,y}` → 4) and nesting (`{a,b{1,2}}` → 3). Patterns without braces are unchanged. Closes [#161](https://github.com/Digital-Process-Tools/claude-supertool/issues/161).
-**`gl-mrs`** — MR triage board: your open MRs + per-MR pipeline status + which already have a `watch` poller running + an actionable footer. Pairs with `watch` to auto-watch every failing MR.
35
36
-**`claude-log-summary:UUID`** — model, duration, tool calls, tokens, cache hit %, errors-by-tool. Audit your own runs.
36
37
37
38
That's a sample. supertool ships ~40 ops out of the box (built-ins + `gitlab` / `github` / `git` / `claude-log` presets) — add your own and you're past 60 fast.
./supertool 'gl-mrs:author=@me,failed,iids'# bare ids of my failing MRs
47
+
```
48
+
The last form feeds the [`watch`](watch.md) supervisor: pipe failing-MR ids straight into background pollers.
49
+
41
50
## Configuration
42
51
52
+
`gl-mrs` enrichment is tunable (parallelism, how many MRs to enrich, page size):
53
+
54
+
```json
55
+
{
56
+
"ops": {
57
+
"gl-mrs": {
58
+
"cmd": "python3 {path}gitlab/mrs.py {args}",
59
+
"enrich_workers": 8,
60
+
"enrich_cap": 40,
61
+
"per_page": 50
62
+
}
63
+
}
64
+
}
65
+
```
66
+
67
+
The list endpoint omits pipeline, approval, and diff data, so each MR costs a couple of `glab api` calls (MR detail + approvals, plus failed-job names for failing MRs). `enrich_workers` threads those calls; `enrich_cap` bounds how many MRs get enriched; `per_page` bounds how many are listed.
68
+
43
69
`gl-job` error pattern search and log tail length are configurable:
`watch:SOURCE:ID` watches one id. To watch *every id a query returns* — e.g. all your failing MRs — pair it with a list op via the bundled supervisor `presets/watch/watch-mine.sh`. It runs a "list mine" op (`gl-mrs`/`gh-prs`), extracts the ids, and spawns one watcher each. Idempotent (the `watch` op skips ids already watched), so it's safe on a loop:
32
+
33
+
```bash
34
+
# default: my failing GitLab MRs → gitlab-mr watchers
35
+
bash presets/watch/watch-mine.sh
36
+
37
+
# re-sync every 5 min from inside Claude Code
38
+
/loop 5m bash presets/watch/watch-mine.sh
39
+
40
+
# any feed op + source — e.g. my failing GitHub PRs (once a gh-prs op exists)
Args: `$1` feed op (default `gl-mrs:author=@me,failed,iids`), `$2` watch source (default `gitlab-mr`), `$3` notify events (default `pipeline_failed,merged`). The separation is deliberate — the list op owns *what's mine* (a platform concern), the watch preset stays generic. The feed op just has to emit bare ids (the `iids` flow); only `gl-mrs` ships today, a `gh-prs` twin is the obvious next one.
0 commit comments