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 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
- Or use with npx:
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
- Analyzes your git changes against all threadlines in the `/threadlines` directory.
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
 
@@ -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 || process.env.THREADLINE_API_URL || 'http://localhost:3000';
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);
@@ -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
- return upstream.replace(/^origin\//, '');
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
- return defaultBranch.replace(/^origin\//, '');
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
- // Fallback to common names
84
- const commonBases = ['main', 'master', 'develop'];
85
- for (const candidate of commonBases) {
86
- try {
87
- await git.revparse([`origin/${candidate}`]);
88
- return candidate;
89
- }
90
- catch {
91
- // Try next
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 <sha>', 'Review specific 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();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "threadlines",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Threadline CLI - AI-powered linter based on your natural language documentation",
5
5
  "main": "dist/index.js",
6
6
  "bin": {