treliq 0.4.0

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.
Files changed (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +340 -0
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +540 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/core/cache.d.ts +29 -0
  8. package/dist/core/cache.d.ts.map +1 -0
  9. package/dist/core/cache.js +64 -0
  10. package/dist/core/cache.js.map +1 -0
  11. package/dist/core/concurrency.d.ts +16 -0
  12. package/dist/core/concurrency.d.ts.map +1 -0
  13. package/dist/core/concurrency.js +60 -0
  14. package/dist/core/concurrency.js.map +1 -0
  15. package/dist/core/db.d.ts +127 -0
  16. package/dist/core/db.d.ts.map +1 -0
  17. package/dist/core/db.js +490 -0
  18. package/dist/core/db.js.map +1 -0
  19. package/dist/core/dedup.d.ts +18 -0
  20. package/dist/core/dedup.d.ts.map +1 -0
  21. package/dist/core/dedup.js +159 -0
  22. package/dist/core/dedup.js.map +1 -0
  23. package/dist/core/graphql.d.ts +30 -0
  24. package/dist/core/graphql.d.ts.map +1 -0
  25. package/dist/core/graphql.js +243 -0
  26. package/dist/core/graphql.js.map +1 -0
  27. package/dist/core/notifications.d.ts +37 -0
  28. package/dist/core/notifications.d.ts.map +1 -0
  29. package/dist/core/notifications.js +174 -0
  30. package/dist/core/notifications.js.map +1 -0
  31. package/dist/core/provider.d.ts +45 -0
  32. package/dist/core/provider.d.ts.map +1 -0
  33. package/dist/core/provider.js +147 -0
  34. package/dist/core/provider.js.map +1 -0
  35. package/dist/core/ratelimit.d.ts +40 -0
  36. package/dist/core/ratelimit.d.ts.map +1 -0
  37. package/dist/core/ratelimit.js +77 -0
  38. package/dist/core/ratelimit.js.map +1 -0
  39. package/dist/core/reputation.d.ts +16 -0
  40. package/dist/core/reputation.d.ts.map +1 -0
  41. package/dist/core/reputation.js +59 -0
  42. package/dist/core/reputation.js.map +1 -0
  43. package/dist/core/scanner.d.ts +58 -0
  44. package/dist/core/scanner.d.ts.map +1 -0
  45. package/dist/core/scanner.js +635 -0
  46. package/dist/core/scanner.js.map +1 -0
  47. package/dist/core/scoring.d.ts +36 -0
  48. package/dist/core/scoring.d.ts.map +1 -0
  49. package/dist/core/scoring.js +360 -0
  50. package/dist/core/scoring.js.map +1 -0
  51. package/dist/core/types.d.ts +89 -0
  52. package/dist/core/types.d.ts.map +1 -0
  53. package/dist/core/types.js +6 -0
  54. package/dist/core/types.js.map +1 -0
  55. package/dist/core/vectorstore.d.ts +42 -0
  56. package/dist/core/vectorstore.d.ts.map +1 -0
  57. package/dist/core/vectorstore.js +149 -0
  58. package/dist/core/vectorstore.js.map +1 -0
  59. package/dist/core/vision.d.ts +16 -0
  60. package/dist/core/vision.d.ts.map +1 -0
  61. package/dist/core/vision.js +41 -0
  62. package/dist/core/vision.js.map +1 -0
  63. package/dist/index.d.ts +21 -0
  64. package/dist/index.d.ts.map +1 -0
  65. package/dist/index.js +34 -0
  66. package/dist/index.js.map +1 -0
  67. package/dist/server/app.d.ts +21 -0
  68. package/dist/server/app.d.ts.map +1 -0
  69. package/dist/server/app.js +284 -0
  70. package/dist/server/app.js.map +1 -0
  71. package/dist/server/index.d.ts +29 -0
  72. package/dist/server/index.d.ts.map +1 -0
  73. package/dist/server/index.js +117 -0
  74. package/dist/server/index.js.map +1 -0
  75. package/dist/server/scheduler.d.ts +26 -0
  76. package/dist/server/scheduler.d.ts.map +1 -0
  77. package/dist/server/scheduler.js +136 -0
  78. package/dist/server/scheduler.js.map +1 -0
  79. package/dist/server/sse.d.ts +33 -0
  80. package/dist/server/sse.d.ts.map +1 -0
  81. package/dist/server/sse.js +80 -0
  82. package/dist/server/sse.js.map +1 -0
  83. package/dist/server/webhooks.d.ts +23 -0
  84. package/dist/server/webhooks.d.ts.map +1 -0
  85. package/dist/server/webhooks.js +175 -0
  86. package/dist/server/webhooks.js.map +1 -0
  87. package/package.json +84 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mahsum Aktaş
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.
package/README.md ADDED
@@ -0,0 +1,340 @@
1
+ <p align="center">
2
+ <img src="docs/logo.png" alt="Treliq" width="140" />
3
+ </p>
4
+
5
+ <h3 align="center">AI-Powered PR Triage for Open Source Maintainers</h3>
6
+
7
+ <p align="center">
8
+ <em>"3,100 PRs. Which ones should I merge?"</em>
9
+ </p>
10
+
11
+ <p align="center">
12
+ <a href="https://www.npmjs.com/package/treliq"><img src="https://img.shields.io/npm/v/treliq?style=flat-square&color=CB3837&logo=npm" alt="npm version" /></a>
13
+ <a href="https://www.npmjs.com/package/treliq"><img src="https://img.shields.io/npm/dm/treliq?style=flat-square&color=CB3837" alt="npm downloads" /></a>
14
+ <a href="https://github.com/mahsumaktas/treliq/actions"><img src="https://img.shields.io/github/actions/workflow/status/mahsumaktas/treliq/ci.yml?branch=main&style=flat-square" alt="CI" /></a>
15
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue?style=flat-square" alt="License: MIT" /></a>
16
+ <img src="https://img.shields.io/badge/TypeScript-5.7-3178C6?style=flat-square&logo=typescript&logoColor=white" alt="TypeScript" />
17
+ <img src="https://img.shields.io/badge/Node.js-≥18-339933?style=flat-square&logo=node.js&logoColor=white" alt="Node.js" />
18
+ <a href="https://github.com/mahsumaktas/treliq/stargazers"><img src="https://img.shields.io/github/stars/mahsumaktas/treliq?style=flat-square" alt="Stars" /></a>
19
+ </p>
20
+
21
+ ---
22
+
23
+ Treliq is an intelligent PR triage system that **deduplicates, scores, and ranks** pull requests so maintainers can focus on merging what matters. Available as a **CLI tool**, **persistent server with REST API**, and **GitHub Action**.
24
+
25
+ ## The Problem
26
+
27
+ Existing tools review code (CodeRabbit, Greptile, Copilot). None answer the maintainer's real questions:
28
+
29
+ - **"These 5 PRs fix the same bug — which one is best?"**
30
+ - **"Does this PR align with our roadmap?"**
31
+ - **"Show me the top 10 PRs I should review today."**
32
+
33
+ Code Review ≠ PR Triage. Treliq fills the gap.
34
+
35
+ ## What's New in v0.4
36
+
37
+ - 🖥️ **Server Mode** — Persistent Fastify server with REST API, dashboard UI, and scheduled scanning
38
+ - 📡 **Real-time SSE** — Live dashboard updates via Server-Sent Events
39
+ - 🔗 **GitHub Webhooks** — Auto-score PRs on open/update/close with HMAC-SHA256 verification
40
+ - 🔍 **GraphQL Fetching** — ~80% fewer API calls using GitHub's GraphQL API
41
+ - 📊 **18-Signal Scoring** — 5 new signals: draft status, milestone, label priority, CODEOWNERS, requested reviewers
42
+ - 🗄️ **SQLite Persistence** — Full scan history, PR state tracking, repository management
43
+ - ⚡ **Parallel LLM Scoring** — Concurrency-controlled parallel scoring with configurable limits
44
+ - 🚦 **Rate Limit Manager** — Intelligent GitHub API pacing with automatic backoff
45
+ - ⏰ **Cron Scheduler** — Automatic periodic scanning with Slack/Discord notifications
46
+ - 📢 **Notifications** — Slack and Discord webhook integration for scan results and high-priority PRs
47
+
48
+ ## Dashboard
49
+
50
+ **[Live Demo →](https://mahsumaktas.github.io/treliq/)**
51
+
52
+ <p align="center">
53
+ <img src="docs/screenshots/dashboard-dark.jpg" alt="Treliq Dashboard" width="800" />
54
+ </p>
55
+
56
+ - 50 PRs scored and ranked at a glance
57
+ - Duplicate cluster visualization
58
+ - Spam detection, conflict status, LLM risk assessment
59
+ - Dark/light theme toggle
60
+
61
+ ## Architecture
62
+
63
+ ```mermaid
64
+ graph TB
65
+ subgraph Ingestion
66
+ GH_REST[GitHub REST API]
67
+ GH_GQL[GitHub GraphQL API]
68
+ WH[GitHub Webhooks]
69
+ end
70
+
71
+ subgraph Core
72
+ Scanner[Scanner]
73
+ Scoring[18-Signal Scoring Engine]
74
+ LLM[Multi-Provider LLM<br/>Gemini · OpenAI · Anthropic]
75
+ Dedup[Embedding Dedup<br/>LanceDB]
76
+ Vision[Vision Doc Alignment]
77
+ Rep[Contributor Reputation]
78
+ end
79
+
80
+ subgraph Persistence
81
+ SQLite[(SQLite)]
82
+ Cache[Incremental Cache]
83
+ end
84
+
85
+ subgraph Server["Server Mode (Fastify)"]
86
+ REST[REST API]
87
+ SSE[SSE Real-time Events]
88
+ Scheduler[Cron Scheduler]
89
+ Notif[Slack / Discord]
90
+ end
91
+
92
+ subgraph Clients
93
+ CLI[CLI]
94
+ Dashboard[Web Dashboard]
95
+ Action[GitHub Action]
96
+ end
97
+
98
+ GH_REST & GH_GQL --> Scanner
99
+ WH --> REST
100
+ Scanner --> Scoring
101
+ Scoring --> LLM
102
+ Scanner --> Dedup
103
+ Scanner --> Vision
104
+ Scoring --> Rep
105
+ Scoring --> SQLite
106
+ Cache --> Scanner
107
+ REST --> Scanner
108
+ REST --> SSE
109
+ Scheduler --> Scanner
110
+ Scheduler --> Notif
111
+ CLI --> Scanner
112
+ Dashboard --> REST
113
+ Dashboard --> SSE
114
+ Action --> CLI
115
+ ```
116
+
117
+ ## Quick Start
118
+
119
+ ### CLI Mode
120
+
121
+ ```bash
122
+ # Score a single PR
123
+ npx treliq score -r owner/repo -n 123 -f markdown
124
+
125
+ # Scan all open PRs (up to 100)
126
+ npx treliq scan -r owner/repo -m 100 -f json
127
+
128
+ # Find duplicate PR clusters
129
+ npx treliq dedup -r owner/repo
130
+
131
+ # Trust known contributors (exempt from spam detection)
132
+ npx treliq scan -r owner/repo --trust-contributors
133
+ ```
134
+
135
+ ### Server Mode
136
+
137
+ ```bash
138
+ # Start server with dashboard on port 4747
139
+ npx treliq server -r owner/repo -p 4747
140
+
141
+ # With webhooks and scheduled scanning
142
+ npx treliq server -r owner/repo -p 4747 \
143
+ --webhook-secret $WEBHOOK_SECRET \
144
+ --schedule "0 */6 * * *" \
145
+ --slack-webhook $SLACK_URL
146
+
147
+ # With multiple scheduled repositories
148
+ npx treliq server -r owner/repo -p 4747 \
149
+ --schedule "0 8 * * *" \
150
+ --scheduled-repos "org/repo1,org/repo2"
151
+ ```
152
+
153
+ The server exposes:
154
+
155
+ | Endpoint | Description |
156
+ |----------|-------------|
157
+ | `GET /` | Dashboard UI |
158
+ | `GET /health` | Health check |
159
+ | `GET /api/repos` | List tracked repositories |
160
+ | `GET /api/repos/:owner/:repo/prs` | List scored PRs (sortable, filterable) |
161
+ | `GET /api/repos/:owner/:repo/prs/:number` | Single PR details |
162
+ | `POST /api/repos/:owner/:repo/scan` | Trigger a new scan |
163
+ | `GET /api/repos/:owner/:repo/scans` | Scan history |
164
+ | `GET /api/repos/:owner/:repo/spam` | Spam PRs |
165
+ | `GET /api/events` | SSE real-time stream |
166
+ | `POST /webhooks` | GitHub webhook receiver |
167
+ | `GET /setup` | GitHub App setup guide |
168
+
169
+ ### Multi-Provider LLM
170
+
171
+ ```bash
172
+ # Default: Gemini Flash
173
+ npx treliq scan -r owner/repo
174
+
175
+ # OpenAI
176
+ npx treliq scan -r owner/repo -p openai --api-key sk-...
177
+
178
+ # Anthropic (embeddings fall back to Gemini/OpenAI)
179
+ npx treliq scan -r owner/repo -p anthropic --api-key sk-ant-...
180
+ ```
181
+
182
+ ## 18-Signal Scoring
183
+
184
+ | # | Signal | Weight | Description |
185
+ |---|--------|--------|-------------|
186
+ | 1 | CI Status | 0.15 | Pass / fail / pending from GitHub Checks |
187
+ | 2 | Test Coverage | 0.12 | Whether test files changed alongside code |
188
+ | 3 | Merge Conflicts | 0.12 | Mergeable / conflicting / unknown |
189
+ | 4 | Contributor Trust | 0.12 | Author association + reputation score |
190
+ | 5 | Spam Detection | 0.12 | Tiny diff, docs-only, AI language markers |
191
+ | 6 | Draft Status | 0.08 | Draft PRs deprioritized |
192
+ | 7 | Review Status | 0.08 | Approved / changes requested / commented |
193
+ | 8 | Label Priority | 0.08 | High-priority labels boosted (p0, critical, security) |
194
+ | 9 | Milestone | 0.07 | PRs attached to milestones score higher |
195
+ | 10 | Diff Size | 0.07 | Lines changed — penalizes extremes |
196
+ | 11 | Staleness | 0.07 | Days since opened — fresh PRs preferred |
197
+ | 12 | Issue References | 0.07 | Links to issues via `Fixes #123` |
198
+ | 13 | CODEOWNERS | 0.05 | Author owns affected code paths |
199
+ | 14 | Requested Reviewers | 0.05 | Reviewers assigned signals process maturity |
200
+ | 15 | Commit Quality | 0.04 | Conventional commit format |
201
+ | 16 | Body Quality | 0.04 | Description length, checklists, screenshots |
202
+ | 17 | Activity | 0.04 | Comment count — engagement signal |
203
+ | 18 | Breaking Change | 0.04 | Risky files, large deletions, `!:` in title |
204
+
205
+ When an LLM provider is configured, a **quality score** (0–100) is blended at **60% LLM / 40% heuristic**.
206
+
207
+ ## GitHub Action
208
+
209
+ ```yaml
210
+ name: Treliq PR Triage
211
+ on:
212
+ pull_request:
213
+ types: [opened, synchronize]
214
+ issue_comment:
215
+ types: [created]
216
+
217
+ permissions:
218
+ contents: read
219
+ pull-requests: write
220
+ issues: write
221
+
222
+ jobs:
223
+ triage:
224
+ if: github.event_name == 'pull_request'
225
+ runs-on: ubuntu-latest
226
+ steps:
227
+ - uses: actions/checkout@v4
228
+ - uses: actions/setup-node@v4
229
+ with:
230
+ node-version: 20
231
+ - run: npm install -g treliq@latest
232
+ - name: Score PR
233
+ id: score
234
+ env:
235
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
236
+ GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
237
+ run: |
238
+ RESULT=$(treliq score -r ${{ github.repository }} -n ${{ github.event.pull_request.number }} -f markdown)
239
+ echo "result<<EOF" >> $GITHUB_OUTPUT
240
+ echo "$RESULT" >> $GITHUB_OUTPUT
241
+ echo "EOF" >> $GITHUB_OUTPUT
242
+ - uses: actions/github-script@v7
243
+ with:
244
+ script: |
245
+ await github.rest.issues.createComment({
246
+ owner: context.repo.owner,
247
+ repo: context.repo.repo,
248
+ issue_number: context.payload.pull_request.number,
249
+ body: process.env.SCORE_RESULT,
250
+ });
251
+ env:
252
+ SCORE_RESULT: ${{ steps.score.outputs.result }}
253
+ ```
254
+
255
+ **PR Commands:** Comment `/treliq score` or `/treliq scan` on any PR.
256
+
257
+ ## Configuration
258
+
259
+ ### Environment Variables
260
+
261
+ | Variable | Provider | Required For |
262
+ |----------|----------|-------------|
263
+ | `GITHUB_TOKEN` | GitHub | All commands |
264
+ | `GEMINI_API_KEY` | Gemini (default) | LLM scoring, embeddings, vision |
265
+ | `OPENAI_API_KEY` | OpenAI | LLM scoring, embeddings |
266
+ | `ANTHROPIC_API_KEY` | Anthropic | LLM scoring (embeddings via fallback) |
267
+
268
+ ### Server Configuration
269
+
270
+ | Flag | Default | Description |
271
+ |------|---------|-------------|
272
+ | `-p, --port` | `4747` | Server port |
273
+ | `--host` | `0.0.0.0` | Bind address |
274
+ | `--webhook-secret` | — | GitHub webhook HMAC secret |
275
+ | `--schedule` | — | Cron expression for auto-scanning |
276
+ | `--scheduled-repos` | — | Comma-separated repos to scan on schedule |
277
+ | `--slack-webhook` | — | Slack notification webhook URL |
278
+ | `--discord-webhook` | — | Discord notification webhook URL |
279
+
280
+ ## SSE Real-time Events
281
+
282
+ Connect to `/api/events` for live updates:
283
+
284
+ ```javascript
285
+ const events = new EventSource('http://localhost:4747/api/events');
286
+
287
+ events.addEventListener('scan_start', (e) => {
288
+ console.log('Scan started:', JSON.parse(e.data));
289
+ });
290
+
291
+ events.addEventListener('scan_complete', (e) => {
292
+ const { repo, totalPRs, spamCount } = JSON.parse(e.data);
293
+ console.log(`Scanned ${totalPRs} PRs, ${spamCount} spam`);
294
+ });
295
+
296
+ events.addEventListener('pr_scored', (e) => {
297
+ const { prNumber, totalScore } = JSON.parse(e.data);
298
+ console.log(`PR #${prNumber} scored ${totalScore}/100`);
299
+ });
300
+ ```
301
+
302
+ ## Webhook Integration
303
+
304
+ 1. Create a GitHub App or webhook at **Settings → Webhooks**
305
+ 2. Set URL to `https://your-server/webhooks`
306
+ 3. Set content type to `application/json`
307
+ 4. Select events: `Pull requests`
308
+ 5. Start server with `--webhook-secret YOUR_SECRET`
309
+
310
+ Treliq automatically scores PRs on `opened`, re-scores on `synchronize`, and updates state on `closed`/`reopened`.
311
+
312
+ ## Inspired By
313
+
314
+ | Tool | What We Learned |
315
+ |------|----------------|
316
+ | [Qodo PR-Agent](https://github.com/qodo-ai/pr-agent) | `/review` command pattern |
317
+ | [Greptile](https://greptile.com) | Full codebase context matters |
318
+ | [ai-duplicate-detector](https://github.com/mackgorski/ai-duplicate-detector) | Embedding threshold system |
319
+
320
+ ## Contributing
321
+
322
+ Contributions welcome! Please:
323
+
324
+ 1. Fork the repository
325
+ 2. Create a feature branch (`git checkout -b feat/amazing-feature`)
326
+ 3. Use conventional commits (`feat:`, `fix:`, `docs:`, etc.)
327
+ 4. Add tests for new functionality
328
+ 5. Open a PR — Treliq will score it automatically 😉
329
+
330
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines.
331
+
332
+ ## License
333
+
334
+ MIT © [Mahsum Aktaş](https://github.com/mahsumaktas)
335
+
336
+ ---
337
+
338
+ <p align="center">
339
+ <em>Built because 3,100 PRs won't triage themselves.</em>
340
+ </p>
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}