threadlines 0.1.7 → 0.1.9
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 +69 -2
- package/dist/commands/check.js +5 -2
- package/dist/commands/init.js +1 -0
- package/dist/git/diff.js +52 -13
- package/dist/index.js +16 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,16 +24,43 @@ Getting teams to follow consistent quality standards is **hard**. Really hard.
|
|
|
24
24
|
|
|
25
25
|
## Installation
|
|
26
26
|
|
|
27
|
+
### Option 1: Global Installation (Recommended for Regular Use)
|
|
28
|
+
|
|
27
29
|
```bash
|
|
28
30
|
npm install -g threadlines
|
|
29
31
|
```
|
|
30
32
|
|
|
31
|
-
|
|
33
|
+
Then use directly:
|
|
34
|
+
```bash
|
|
35
|
+
threadlines check
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Option 2: Use with npx (No Installation)
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npx threadlines check
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**For non-interactive environments** (CI/CD, AI assistants like Cursor):
|
|
45
|
+
```bash
|
|
46
|
+
npx --yes threadlines check
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The `--yes` flag auto-confirms package installation, preventing prompts that block automation.
|
|
50
|
+
|
|
51
|
+
### Option 3: Local Project Dependency (Recommended for Teams)
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npm install --save-dev threadlines
|
|
55
|
+
```
|
|
32
56
|
|
|
57
|
+
Then use:
|
|
33
58
|
```bash
|
|
34
59
|
npx threadlines check
|
|
35
60
|
```
|
|
36
61
|
|
|
62
|
+
This ensures everyone on your team uses the same version.
|
|
63
|
+
|
|
37
64
|
## Quick Start
|
|
38
65
|
|
|
39
66
|
### 1. Initialize Your First Threadline
|
|
@@ -88,10 +115,50 @@ Creates a template threadline file to get you started. The command will:
|
|
|
88
115
|
threadlines check
|
|
89
116
|
```
|
|
90
117
|
|
|
91
|
-
|
|
118
|
+
By default, analyzes your staged/unstaged git changes against all threadlines in the `/threadlines` directory.
|
|
119
|
+
|
|
120
|
+
**Common Use Cases:**
|
|
121
|
+
|
|
122
|
+
**Check latest commit locally:**
|
|
123
|
+
```bash
|
|
124
|
+
threadlines check --commit HEAD
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Check a specific commit:**
|
|
128
|
+
```bash
|
|
129
|
+
threadlines check --commit abc123def
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
**Check all commits in a branch:**
|
|
133
|
+
```bash
|
|
134
|
+
threadlines check --branch feature/new-feature
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Check entire file(s):**
|
|
138
|
+
```bash
|
|
139
|
+
threadlines check --file src/api/users.ts
|
|
140
|
+
threadlines check --files src/api/users.ts src/api/posts.ts
|
|
141
|
+
threadlines check --folder src/api
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**Show all results (not just violations):**
|
|
145
|
+
```bash
|
|
146
|
+
threadlines check --full
|
|
147
|
+
```
|
|
92
148
|
|
|
93
149
|
**Options:**
|
|
94
150
|
- `--api-url <url>` - Override the server URL (default: http://localhost:3000)
|
|
151
|
+
- `--commit <ref>` - Review specific commit. Accepts commit SHA or git reference (e.g., `HEAD`, `HEAD~1`, `abc123`)
|
|
152
|
+
- `--branch <name>` - Review all commits in branch vs base
|
|
153
|
+
- `--file <path>` - Review entire file (all lines as additions)
|
|
154
|
+
- `--folder <path>` - Review all files in folder recursively
|
|
155
|
+
- `--files <paths...>` - Review multiple specified files
|
|
156
|
+
- `--full` - Show all results (compliant, attention, not_relevant). Default: only attention items
|
|
157
|
+
|
|
158
|
+
**Auto-detection in CI:**
|
|
159
|
+
- CI with branch detected → reviews all commits in branch vs base
|
|
160
|
+
- CI with commit SHA detected → reviews specific commit
|
|
161
|
+
- Local development → reviews staged/unstaged changes
|
|
95
162
|
|
|
96
163
|
## Configuration
|
|
97
164
|
|
package/dist/commands/check.js
CHANGED
|
@@ -195,8 +195,11 @@ async function checkCommand(options) {
|
|
|
195
195
|
// 4. Get repo name and branch name
|
|
196
196
|
const repoName = await (0, repo_1.getRepoName)(repoRoot);
|
|
197
197
|
const branchName = await (0, repo_1.getBranchName)(repoRoot);
|
|
198
|
-
// 5. Get API URL
|
|
199
|
-
const apiUrl = options.apiUrl ||
|
|
198
|
+
// 5. Get API URL (auto-detect Vercel if available)
|
|
199
|
+
const apiUrl = options.apiUrl ||
|
|
200
|
+
process.env.THREADLINE_API_URL ||
|
|
201
|
+
(process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : null) ||
|
|
202
|
+
'http://localhost:3000';
|
|
200
203
|
// 6. Call review API
|
|
201
204
|
console.log(chalk_1.default.gray('🤖 Running threadline checks...'));
|
|
202
205
|
const client = new client_1.ReviewAPIClient(apiUrl);
|
package/dist/commands/init.js
CHANGED
|
@@ -105,6 +105,7 @@ async function initCommand() {
|
|
|
105
105
|
console.log(chalk_1.default.white(' Make sure .env.local is in your .gitignore file!'));
|
|
106
106
|
console.log('');
|
|
107
107
|
console.log(chalk_1.default.gray(' 3. Run: npx threadlines check'));
|
|
108
|
+
console.log(chalk_1.default.gray(' (Use npx --yes threadlines check in non-interactive environments)'));
|
|
108
109
|
}
|
|
109
110
|
catch (error) {
|
|
110
111
|
console.error(chalk_1.default.red(`\n❌ Error: ${error.message}`));
|
package/dist/git/diff.js
CHANGED
|
@@ -63,6 +63,33 @@ async function getBranchDiff(repoRoot, branchName, baseBranch) {
|
|
|
63
63
|
base = baseBranch;
|
|
64
64
|
}
|
|
65
65
|
else {
|
|
66
|
+
// Check if the branch itself is a base branch (main/master)
|
|
67
|
+
const baseBranchNames = ['main', 'master'];
|
|
68
|
+
const isBaseBranch = baseBranchNames.includes(branchName.toLowerCase());
|
|
69
|
+
if (isBaseBranch) {
|
|
70
|
+
// For main/master branch, compare against previous commit (HEAD~1)
|
|
71
|
+
// This checks what changed in the most recent commit
|
|
72
|
+
try {
|
|
73
|
+
const previousCommit = await git.revparse(['HEAD~1']).catch(() => null);
|
|
74
|
+
if (previousCommit) {
|
|
75
|
+
// Use commit-based diff instead
|
|
76
|
+
const diff = await git.diff([`${previousCommit}..HEAD`]);
|
|
77
|
+
const diffSummary = await git.diffSummary([`${previousCommit}..HEAD`]);
|
|
78
|
+
const changedFiles = diffSummary.files.map(f => f.file);
|
|
79
|
+
return {
|
|
80
|
+
diff: diff || '',
|
|
81
|
+
changedFiles
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// If no previous commit, return empty (first commit)
|
|
87
|
+
return {
|
|
88
|
+
diff: '',
|
|
89
|
+
changedFiles: []
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
66
93
|
// Try to detect base branch: upstream, default branch, or common names
|
|
67
94
|
base = await detectBaseBranch(git, branchName);
|
|
68
95
|
}
|
|
@@ -72,27 +99,39 @@ async function getBranchDiff(repoRoot, branchName, baseBranch) {
|
|
|
72
99
|
const upstream = await git.revparse(['--abbrev-ref', '--symbolic-full-name', `${branchName}@{u}`]).catch(() => null);
|
|
73
100
|
if (upstream) {
|
|
74
101
|
// Extract base from upstream (e.g., "origin/main" -> "main")
|
|
75
|
-
|
|
102
|
+
const upstreamBranch = upstream.replace(/^origin\//, '');
|
|
103
|
+
// Don't use the branch itself as its base
|
|
104
|
+
if (upstreamBranch !== branchName) {
|
|
105
|
+
return upstreamBranch;
|
|
106
|
+
}
|
|
76
107
|
}
|
|
77
108
|
// Try default branch
|
|
78
109
|
try {
|
|
79
110
|
const defaultBranch = await git.revparse(['--abbrev-ref', 'refs/remotes/origin/HEAD']);
|
|
80
|
-
|
|
111
|
+
const defaultBranchName = defaultBranch.replace(/^origin\//, '');
|
|
112
|
+
// Don't use the branch itself as its base
|
|
113
|
+
if (defaultBranchName !== branchName) {
|
|
114
|
+
return defaultBranchName;
|
|
115
|
+
}
|
|
81
116
|
}
|
|
82
117
|
catch {
|
|
83
|
-
//
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
118
|
+
// Continue to fallback
|
|
119
|
+
}
|
|
120
|
+
// Fallback to common names (excluding the branch itself)
|
|
121
|
+
const commonBases = ['main', 'master', 'develop'];
|
|
122
|
+
for (const candidate of commonBases) {
|
|
123
|
+
if (candidate.toLowerCase() === branchName.toLowerCase()) {
|
|
124
|
+
continue; // Skip if it's the same branch
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
await git.revparse([`origin/${candidate}`]);
|
|
128
|
+
return candidate;
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
// Try next
|
|
93
132
|
}
|
|
94
|
-
throw new Error(`Could not determine base branch. Please specify with --base flag or set upstream tracking.`);
|
|
95
133
|
}
|
|
134
|
+
throw new Error(`Could not determine base branch for '${branchName}'. Please specify with --base flag or set upstream tracking.`);
|
|
96
135
|
}
|
|
97
136
|
// Get diff between base and branch (cumulative diff of all commits)
|
|
98
137
|
// Format: git diff base...branch (three-dot notation finds common ancestor)
|
package/dist/index.js
CHANGED
|
@@ -61,12 +61,25 @@ program
|
|
|
61
61
|
program
|
|
62
62
|
.command('check')
|
|
63
63
|
.description('Check code against your threadlines')
|
|
64
|
-
.option('--api-url <url>', 'Threadline server URL', process.env.THREADLINE_API_URL || 'http://localhost:3000')
|
|
64
|
+
.option('--api-url <url>', 'Threadline server URL', process.env.THREADLINE_API_URL || (process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : 'http://localhost:3000'))
|
|
65
65
|
.option('--full', 'Show all results (compliant, attention, not_relevant). Default: only attention items')
|
|
66
|
-
.option('--branch <name>', 'Review all commits in branch vs base')
|
|
67
|
-
.option('--commit <
|
|
66
|
+
.option('--branch <name>', 'Review all commits in branch vs base (e.g., --branch feature/new-feature)')
|
|
67
|
+
.option('--commit <ref>', 'Review specific commit. Accepts commit SHA or git reference (e.g., HEAD, HEAD~1, abc123). Example: --commit HEAD')
|
|
68
68
|
.option('--file <path>', 'Review entire file (all lines as additions)')
|
|
69
69
|
.option('--folder <path>', 'Review all files in folder recursively')
|
|
70
70
|
.option('--files <paths...>', 'Review multiple specified files')
|
|
71
|
+
.addHelpText('after', `
|
|
72
|
+
Examples:
|
|
73
|
+
$ threadlines check # Check staged/unstaged changes (local dev)
|
|
74
|
+
$ threadlines check --commit HEAD # Check latest commit locally
|
|
75
|
+
$ threadlines check --branch main # Check all commits in branch vs base
|
|
76
|
+
$ threadlines check --file src/api.ts # Check entire file
|
|
77
|
+
$ threadlines check --full # Show all results (not just attention items)
|
|
78
|
+
|
|
79
|
+
Auto-detection in CI:
|
|
80
|
+
- CI with branch detected → reviews all commits in branch vs base
|
|
81
|
+
- CI with commit SHA detected → reviews specific commit
|
|
82
|
+
- Local development → reviews staged/unstaged changes
|
|
83
|
+
`)
|
|
71
84
|
.action(check_1.checkCommand);
|
|
72
85
|
program.parse();
|