threadlines 0.2.25 → 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.
- package/README.md +87 -42
- package/dist/api/client.js +49 -12
- package/dist/commands/check.js +147 -105
- package/dist/commands/init.js +32 -23
- package/dist/git/ci-context.js +6 -8
- package/dist/git/diff.js +60 -25
- package/dist/git/local.js +195 -42
- package/dist/llm/prompt-builder.js +72 -0
- package/dist/processors/expert.js +120 -0
- package/dist/processors/single-expert.js +253 -0
- package/dist/utils/config-file.js +27 -17
- package/dist/utils/config.js +20 -14
- package/dist/utils/diff-filter.js +105 -0
- package/dist/utils/logger.js +13 -6
- package/dist/utils/slim-diff.js +133 -0
- package/package.json +2 -4
package/README.md
CHANGED
|
@@ -4,17 +4,17 @@ Threadline CLI - AI-powered linter based on your natural language documentation.
|
|
|
4
4
|
|
|
5
5
|
## Why Threadline?
|
|
6
6
|
|
|
7
|
-
Getting teams to follow
|
|
7
|
+
Getting teams to consistently follow coding patterns and quality standards is **hard**. Really hard.
|
|
8
8
|
|
|
9
9
|
- **Documentation** → Nobody reads it. Or it's outdated before you finish writing it.
|
|
10
10
|
- **Linting** → Catches syntax errors, but misses nuanced stuff.
|
|
11
11
|
- **AI Code Reviewers** → Powerful, but you can't trust them. Did they actually check what you care about? Can you customize them with your team's specific rules?
|
|
12
12
|
|
|
13
|
-
**Threadline solves this** by running **separate, parallel, highly focused AI-powered reviews** - each focused on a single, specific concern. Your coding
|
|
13
|
+
**Threadline solves this** by running **separate, parallel, highly focused AI-powered reviews** - each focused on a single, specific concern or pattern: the stuff that takes engineers months to internalise - and they keep forgetting. Your coding patterns live in your repository as 'Threadline' markdown files, version-controlled and always in sync with your codebase. Each threadline is its own AI agent, ensuring focused attention on what matters to your team.
|
|
14
14
|
|
|
15
15
|
### What Makes Threadline Different?
|
|
16
16
|
|
|
17
|
-
- **Focused Reviews** - Instead of one AI
|
|
17
|
+
- **Focused Reviews** - Instead of one AI agent checking everything, Threadline runs multiple specialized AI reviewers in parallel. Each threadline focuses on one thing and does it well.
|
|
18
18
|
|
|
19
19
|
- **Documentation That Lives With Your Code** - Your coding standards live in your repo, in a `/threadlines` folder. They're version-controlled, reviewable, and always in sync with your codebase.
|
|
20
20
|
|
|
@@ -24,18 +24,7 @@ Getting teams to follow consistent quality standards is **hard**. Really hard.
|
|
|
24
24
|
|
|
25
25
|
## Installation
|
|
26
26
|
|
|
27
|
-
### Option 1:
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
npm install -g threadlines
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Then use directly:
|
|
34
|
-
```bash
|
|
35
|
-
threadlines check
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
### Option 2: Use with npx (No Installation)
|
|
27
|
+
### Option 1: Use with npx (No Installation)
|
|
39
28
|
|
|
40
29
|
```bash
|
|
41
30
|
npx threadlines check
|
|
@@ -82,8 +71,17 @@ Edit `threadlines/example.md` with your coding standards, then rename it to some
|
|
|
82
71
|
```bash
|
|
83
72
|
npx threadlines check
|
|
84
73
|
```
|
|
74
|
+
|
|
85
75
|
By default, analyzes your staged/unstaged git changes against all threadlines in the `/threadlines` directory.
|
|
86
76
|
|
|
77
|
+
**Review Context Types:**
|
|
78
|
+
- `local` - Staged/unstaged changes (default for local development)
|
|
79
|
+
- `commit` - Specific commit (when using `--commit` flag)
|
|
80
|
+
- `pr` - Pull Request/Merge Request (auto-detected in CI)
|
|
81
|
+
- `file` - Single file (when using `--file` flag)
|
|
82
|
+
- `folder` - Folder contents (when using `--folder` flag)
|
|
83
|
+
- `files` - Multiple files (when using `--files` flag)
|
|
84
|
+
|
|
87
85
|
**Common Use Cases:**
|
|
88
86
|
|
|
89
87
|
**Check latest commit locally:**
|
|
@@ -96,11 +94,6 @@ threadlines check --commit HEAD
|
|
|
96
94
|
threadlines check --commit abc123def
|
|
97
95
|
```
|
|
98
96
|
|
|
99
|
-
**Check all commits in a branch:**
|
|
100
|
-
```bash
|
|
101
|
-
threadlines check --branch feature/new-feature
|
|
102
|
-
```
|
|
103
|
-
|
|
104
97
|
**Check entire file(s):**
|
|
105
98
|
```bash
|
|
106
99
|
threadlines check --file src/api/users.ts
|
|
@@ -108,24 +101,35 @@ threadlines check --files src/api/users.ts src/api/posts.ts
|
|
|
108
101
|
threadlines check --folder src/api
|
|
109
102
|
```
|
|
110
103
|
|
|
104
|
+
**Debug mode (verbose output):**
|
|
105
|
+
```bash
|
|
106
|
+
threadlines check --debug
|
|
107
|
+
```
|
|
108
|
+
|
|
111
109
|
**Show all results (not just violations):**
|
|
112
110
|
```bash
|
|
113
111
|
threadlines check --full
|
|
114
112
|
```
|
|
115
113
|
|
|
114
|
+
**Enable debug logging:**
|
|
115
|
+
```bash
|
|
116
|
+
threadlines check --debug
|
|
117
|
+
```
|
|
118
|
+
|
|
116
119
|
**Options:**
|
|
117
|
-
- `--
|
|
118
|
-
- `--
|
|
119
|
-
- `--
|
|
120
|
-
- `--
|
|
121
|
-
- `--folder <path>` - Review all files in folder recursively
|
|
122
|
-
- `--files <paths...>` - Review multiple specified files
|
|
120
|
+
- `--commit <ref>` - Review specific commit. Accepts commit SHA or git reference (e.g., `HEAD`, `HEAD~1`, `abc123`). Sets review context to `commit`.
|
|
121
|
+
- `--file <path>` - Review entire file (all lines as additions). Sets review context to `file`.
|
|
122
|
+
- `--folder <path>` - Review all files in folder recursively. Sets review context to `folder`.
|
|
123
|
+
- `--files <paths...>` - Review multiple specified files. Sets review context to `files`.
|
|
123
124
|
- `--full` - Show all results (compliant, attention, not_relevant). Default: only attention items
|
|
125
|
+
- `--debug` - Enable debug logging (verbose output for troubleshooting)
|
|
126
|
+
|
|
127
|
+
**Note:** Flags (`--commit`, `--file`, `--folder`, `--files`) are for local development only. In CI/CD environments, these flags are ignored and the CLI auto-detects the appropriate context.
|
|
124
128
|
|
|
125
129
|
**Auto-detection in CI:**
|
|
126
|
-
-
|
|
127
|
-
-
|
|
128
|
-
- Local development →
|
|
130
|
+
- **Pull Request/Merge Request context** → Reviews all changes in the PR/MR (review context: `pr`)
|
|
131
|
+
- **Push to any branch** → Reviews the commit being pushed (review context: `commit`)
|
|
132
|
+
- **Local development** → Reviews staged/unstaged changes (review context: `local`)
|
|
129
133
|
|
|
130
134
|
## Configuration
|
|
131
135
|
|
|
@@ -135,11 +139,40 @@ threadlines check --full
|
|
|
135
139
|
|----------|---------|----------|
|
|
136
140
|
| `THREADLINE_API_KEY` | Authentication with Threadlines API | Yes |
|
|
137
141
|
| `THREADLINE_ACCOUNT` | Your Threadlines account email | Yes |
|
|
138
|
-
| `THREADLINE_API_URL` | Custom API endpoint (default: https://devthreadline.com) | No |
|
|
139
142
|
|
|
140
143
|
Both required variables can be set in a `.env.local` file (recommended for local development) or as environment variables (required for CI/CD).
|
|
141
144
|
|
|
142
|
-
|
|
145
|
+
**Local Development:**
|
|
146
|
+
Create a `.env.local` file in your project root:
|
|
147
|
+
```bash
|
|
148
|
+
THREADLINE_API_KEY=your-api-key-here
|
|
149
|
+
THREADLINE_ACCOUNT=your-email@example.com
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**CI/CD:**
|
|
153
|
+
Set these as environment variables in your platform:
|
|
154
|
+
- **GitHub Actions**: Settings → Secrets → Add variables
|
|
155
|
+
- **GitLab CI**: Settings → CI/CD → Variables
|
|
156
|
+
- **Bitbucket Pipelines**: Repository settings → Repository variables
|
|
157
|
+
- **Vercel**: Settings → Environment Variables
|
|
158
|
+
|
|
159
|
+
Get your credentials at: https://devthreadline.com/settings
|
|
160
|
+
|
|
161
|
+
### Configuration File (`.threadlinerc`)
|
|
162
|
+
|
|
163
|
+
You can customize the API endpoint and other settings by creating a `.threadlinerc` file in your project root:
|
|
164
|
+
|
|
165
|
+
```json
|
|
166
|
+
{
|
|
167
|
+
"mode": "online",
|
|
168
|
+
"api_url": "https://devthreadline.com",
|
|
169
|
+
"openai_model": "gpt-5.2",
|
|
170
|
+
"openai_service_tier": "Flex",
|
|
171
|
+
"diff_context_lines": 10
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
The `api_url` field allows you to point to a custom server if needed. Default is `https://devthreadline.com`.
|
|
143
176
|
|
|
144
177
|
## Threadline Files
|
|
145
178
|
|
|
@@ -176,26 +209,38 @@ Your guidelines and standards here...
|
|
|
176
209
|
|
|
177
210
|
- **`context_files`**: Array of file paths that provide context (always included, even if unchanged)
|
|
178
211
|
|
|
179
|
-
### Example:
|
|
212
|
+
### Example: Feature Flagging Standards
|
|
180
213
|
|
|
181
214
|
```markdown
|
|
182
215
|
---
|
|
183
|
-
id:
|
|
216
|
+
id: feature-flags
|
|
184
217
|
version: 1.0.0
|
|
185
218
|
patterns:
|
|
186
|
-
- "**/
|
|
187
|
-
- "
|
|
219
|
+
- "**/features/**"
|
|
220
|
+
- "**/components/**"
|
|
221
|
+
- "**/*.tsx"
|
|
222
|
+
- "**/*.ts"
|
|
188
223
|
context_files:
|
|
189
|
-
- "
|
|
224
|
+
- "config/feature-flags.ts"
|
|
190
225
|
---
|
|
191
226
|
|
|
192
|
-
#
|
|
227
|
+
# Feature Flag Standards
|
|
228
|
+
|
|
229
|
+
All feature flag usage must:
|
|
230
|
+
- Check flags using the centralized `isFeatureEnabled()` function from `config/feature-flags.ts`
|
|
231
|
+
- Never hardcode feature flag names as strings (use constants from the config)
|
|
232
|
+
- Include proper cleanup: remove feature flag checks when features are fully rolled out
|
|
233
|
+
- Document rollout plan in PR description (target percentage, timeline)
|
|
234
|
+
- Use feature flags for gradual rollouts, not as permanent configuration
|
|
193
235
|
|
|
194
|
-
|
|
195
|
-
-
|
|
196
|
-
-
|
|
197
|
-
-
|
|
236
|
+
**Violations:**
|
|
237
|
+
- ❌ `if (process.env.NEW_FEATURE === 'true')` (hardcoded, not using registry)
|
|
238
|
+
- ❌ `if (flags['new-feature'])` (string literal instead of constant)
|
|
239
|
+
- ✅ `if (isFeatureEnabled(FeatureFlags.NEW_DASHBOARD))` (using centralized function)
|
|
198
240
|
```
|
|
199
241
|
|
|
200
|
-
The `
|
|
242
|
+
The `config/feature-flags.ts` file will always be included as context, ensuring the AI reviewer can verify that:
|
|
243
|
+
- Feature flag names match the registry
|
|
244
|
+
- The correct flag checking function is used
|
|
245
|
+
- Flags are properly typed and documented
|
|
201
246
|
|
package/dist/api/client.js
CHANGED
|
@@ -1,23 +1,60 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.ReviewAPIClient = void 0;
|
|
7
|
-
const axios_1 = __importDefault(require("axios"));
|
|
8
4
|
class ReviewAPIClient {
|
|
9
5
|
constructor(baseURL) {
|
|
10
|
-
this.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
6
|
+
this.timeout = 60000; // 60s timeout for entire request
|
|
7
|
+
this.baseURL = baseURL;
|
|
8
|
+
}
|
|
9
|
+
async fetchWithTimeout(url, options) {
|
|
10
|
+
const controller = new AbortController();
|
|
11
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
12
|
+
try {
|
|
13
|
+
const response = await fetch(url, {
|
|
14
|
+
...options,
|
|
15
|
+
signal: controller.signal,
|
|
16
|
+
});
|
|
17
|
+
clearTimeout(timeoutId);
|
|
18
|
+
return response;
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
clearTimeout(timeoutId);
|
|
22
|
+
// Handle AbortError from timeout
|
|
23
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
24
|
+
throw new Error(`Request timeout after ${this.timeout}ms`);
|
|
15
25
|
}
|
|
16
|
-
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
17
28
|
}
|
|
18
29
|
async review(request) {
|
|
19
|
-
const
|
|
20
|
-
|
|
30
|
+
const url = `${this.baseURL}/api/threadline-check`;
|
|
31
|
+
const response = await this.fetchWithTimeout(url, {
|
|
32
|
+
method: 'POST',
|
|
33
|
+
headers: {
|
|
34
|
+
'Content-Type': 'application/json',
|
|
35
|
+
},
|
|
36
|
+
body: JSON.stringify(request),
|
|
37
|
+
});
|
|
38
|
+
if (!response.ok) {
|
|
39
|
+
const errorText = await response.text();
|
|
40
|
+
throw new Error(`HTTP ${response.status}: ${errorText}`);
|
|
41
|
+
}
|
|
42
|
+
return await response.json();
|
|
43
|
+
}
|
|
44
|
+
async syncResults(request) {
|
|
45
|
+
const url = `${this.baseURL}/api/threadline-check-results`;
|
|
46
|
+
const response = await this.fetchWithTimeout(url, {
|
|
47
|
+
method: 'POST',
|
|
48
|
+
headers: {
|
|
49
|
+
'Content-Type': 'application/json',
|
|
50
|
+
},
|
|
51
|
+
body: JSON.stringify(request),
|
|
52
|
+
});
|
|
53
|
+
if (!response.ok) {
|
|
54
|
+
const errorText = await response.text();
|
|
55
|
+
throw new Error(`HTTP ${response.status}: ${errorText}`);
|
|
56
|
+
}
|
|
57
|
+
return await response.json();
|
|
21
58
|
}
|
|
22
59
|
}
|
|
23
60
|
exports.ReviewAPIClient = ReviewAPIClient;
|