threadlines 0.1.11 → 0.1.13

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.
@@ -47,6 +47,26 @@ const config_1 = require("../utils/config");
47
47
  const fs = __importStar(require("fs"));
48
48
  const path = __importStar(require("path"));
49
49
  const chalk_1 = __importDefault(require("chalk"));
50
+ /**
51
+ * Detect the environment where the check is being run
52
+ * Returns: 'vercel', 'github', 'gitlab', or 'local'
53
+ */
54
+ function detectEnvironment() {
55
+ // Vercel: VERCEL env var is always set in Vercel builds
56
+ if (process.env.VERCEL) {
57
+ return 'vercel';
58
+ }
59
+ // GitHub Actions: GITHUB_ACTIONS env var is always set
60
+ if (process.env.GITHUB_ACTIONS) {
61
+ return 'github';
62
+ }
63
+ // GitLab CI: GITLAB_CI env var is always set, or CI is set with GitLab-specific vars
64
+ if (process.env.GITLAB_CI || (process.env.CI && process.env.CI_COMMIT_SHA)) {
65
+ return 'gitlab';
66
+ }
67
+ // Local development: none of the above
68
+ return 'local';
69
+ }
50
70
  async function checkCommand(options) {
51
71
  const repoRoot = process.cwd();
52
72
  console.log(chalk_1.default.blue('🔍 Threadline: Checking code against your threadlines...\n'));
@@ -89,6 +109,9 @@ async function checkCommand(options) {
89
109
  // 2. Determine review target and get git diff
90
110
  let gitDiff;
91
111
  let reviewContext = { type: 'local' };
112
+ let commitSha = undefined;
113
+ let commitMessage = undefined;
114
+ let prTitle = undefined;
92
115
  // Validate mutually exclusive flags
93
116
  const explicitFlags = [options.branch, options.commit, options.file, options.folder, options.files].filter(Boolean);
94
117
  if (explicitFlags.length > 1) {
@@ -121,6 +144,12 @@ async function checkCommand(options) {
121
144
  console.log(chalk_1.default.gray(`📝 Collecting git changes for commit: ${options.commit}...`));
122
145
  gitDiff = await (0, diff_1.getCommitDiff)(repoRoot, options.commit);
123
146
  reviewContext = { type: 'commit', value: options.commit };
147
+ commitSha = options.commit;
148
+ // Fetch commit message (reliable when we have SHA)
149
+ const message = await (0, diff_1.getCommitMessage)(repoRoot, options.commit);
150
+ if (message) {
151
+ commitMessage = message;
152
+ }
124
153
  }
125
154
  else {
126
155
  // Auto-detect CI environment or use local changes
@@ -131,6 +160,10 @@ async function checkCommand(options) {
131
160
  console.log(chalk_1.default.gray(`📝 Collecting git changes for ${autoTarget.type.toUpperCase()}: ${autoTarget.value}...`));
132
161
  gitDiff = await (0, diff_1.getPRMRDiff)(repoRoot, autoTarget.sourceBranch, autoTarget.targetBranch);
133
162
  reviewContext = { type: autoTarget.type, value: autoTarget.value };
163
+ // Use PR title from GitLab CI (reliable env var)
164
+ if (autoTarget.prTitle) {
165
+ prTitle = autoTarget.prTitle;
166
+ }
134
167
  }
135
168
  else if (autoTarget.type === 'branch') {
136
169
  // Branch: use branch vs base
@@ -143,6 +176,12 @@ async function checkCommand(options) {
143
176
  console.log(chalk_1.default.gray(`📝 Collecting git changes for commit: ${autoTarget.value}...`));
144
177
  gitDiff = await (0, diff_1.getCommitDiff)(repoRoot, autoTarget.value);
145
178
  reviewContext = { type: 'commit', value: autoTarget.value };
179
+ commitSha = autoTarget.value;
180
+ // Fetch commit message (reliable when we have SHA)
181
+ const message = await (0, diff_1.getCommitMessage)(repoRoot, autoTarget.value);
182
+ if (message) {
183
+ commitMessage = message;
184
+ }
146
185
  }
147
186
  else {
148
187
  // Fallback: local development
@@ -195,14 +234,14 @@ async function checkCommand(options) {
195
234
  // 4. Get repo name and branch name
196
235
  const repoName = await (0, repo_1.getRepoName)(repoRoot);
197
236
  const branchName = await (0, repo_1.getBranchName)(repoRoot);
198
- // 5. Get API URL (auto-detect Vercel if available)
237
+ // 5. Get API URL
199
238
  const apiUrl = options.apiUrl ||
200
239
  process.env.THREADLINE_API_URL ||
201
- (process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : null) ||
202
- 'http://localhost:3000';
240
+ 'https://devthreadline.com';
203
241
  // 6. Call review API
204
242
  console.log(chalk_1.default.gray('🤖 Running threadline checks...'));
205
243
  const client = new client_1.ReviewAPIClient(apiUrl);
244
+ const environment = detectEnvironment();
206
245
  const response = await client.review({
207
246
  threadlines: threadlinesWithContext,
208
247
  diff: gitDiff.diff,
@@ -210,7 +249,11 @@ async function checkCommand(options) {
210
249
  apiKey,
211
250
  account,
212
251
  repoName: repoName || undefined,
213
- branchName: branchName || undefined
252
+ branchName: branchName || undefined,
253
+ commitSha: commitSha,
254
+ commitMessage: commitMessage,
255
+ prTitle: prTitle,
256
+ environment: environment
214
257
  });
215
258
  // 7. Display results (with filtering if --full not specified)
216
259
  displayResults(response, options.full || false);
package/dist/git/diff.js CHANGED
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.getGitDiff = getGitDiff;
7
7
  exports.getBranchDiff = getBranchDiff;
8
+ exports.getCommitMessage = getCommitMessage;
8
9
  exports.getCommitDiff = getCommitDiff;
9
10
  exports.getPRMRDiff = getPRMRDiff;
10
11
  const simple_git_1 = __importDefault(require("simple-git"));
@@ -23,11 +24,11 @@ async function getGitDiff(repoRoot) {
23
24
  let diff;
24
25
  if (status.staged.length > 0) {
25
26
  // Use staged changes
26
- diff = await git.diff(['--cached']);
27
+ diff = await git.diff(['--cached', '-U200']);
27
28
  }
28
29
  else if (status.files.length > 0) {
29
30
  // Use unstaged changes
30
- diff = await git.diff();
31
+ diff = await git.diff(['-U200']);
31
32
  }
32
33
  else {
33
34
  // No changes
@@ -73,7 +74,7 @@ async function getBranchDiff(repoRoot, branchName, baseBranch) {
73
74
  const previousCommit = await git.revparse(['HEAD~1']).catch(() => null);
74
75
  if (previousCommit) {
75
76
  // Use commit-based diff instead
76
- const diff = await git.diff([`${previousCommit}..HEAD`]);
77
+ const diff = await git.diff([`${previousCommit}..HEAD`, '-U200']);
77
78
  const diffSummary = await git.diffSummary([`${previousCommit}..HEAD`]);
78
79
  const changedFiles = diffSummary.files.map(f => f.file);
79
80
  return {
@@ -135,7 +136,7 @@ async function getBranchDiff(repoRoot, branchName, baseBranch) {
135
136
  }
136
137
  // Get diff between base and branch (cumulative diff of all commits)
137
138
  // Format: git diff base...branch (three-dot notation finds common ancestor)
138
- const diff = await git.diff([`${base}...${branchName}`]);
139
+ const diff = await git.diff([`${base}...${branchName}`, '-U200']);
139
140
  // Get list of changed files
140
141
  const diffSummary = await git.diffSummary([`${base}...${branchName}`]);
141
142
  const changedFiles = diffSummary.files.map(f => f.file);
@@ -144,6 +145,22 @@ async function getBranchDiff(repoRoot, branchName, baseBranch) {
144
145
  changedFiles
145
146
  };
146
147
  }
148
+ /**
149
+ * Get commit message for a specific commit SHA
150
+ * Returns full commit message (subject + body) or null if commit not found
151
+ */
152
+ async function getCommitMessage(repoRoot, sha) {
153
+ const git = (0, simple_git_1.default)(repoRoot);
154
+ try {
155
+ // Get full commit message (subject + body)
156
+ const message = await git.show([sha, '--format=%B', '--no-patch']);
157
+ return message.trim() || null;
158
+ }
159
+ catch (error) {
160
+ // Commit not found or invalid
161
+ return null;
162
+ }
163
+ }
147
164
  /**
148
165
  * Get diff for a specific commit
149
166
  */
@@ -160,7 +177,7 @@ async function getCommitDiff(repoRoot, sha) {
160
177
  let changedFiles;
161
178
  try {
162
179
  // Get diff using git show
163
- diff = await git.show([sha, '--format=', '--no-color']);
180
+ diff = await git.show([sha, '--format=', '--no-color', '-U200']);
164
181
  // Get changed files using git show --name-only
165
182
  const commitFiles = await git.show([sha, '--name-only', '--format=', '--pretty=format:']);
166
183
  changedFiles = commitFiles
@@ -171,7 +188,7 @@ async function getCommitDiff(repoRoot, sha) {
171
188
  catch (error) {
172
189
  // Fallback: try git diff format
173
190
  try {
174
- diff = await git.diff([`${sha}^..${sha}`]);
191
+ diff = await git.diff([`${sha}^..${sha}`, '-U200']);
175
192
  // Get files from diff summary
176
193
  const diffSummary = await git.diffSummary([`${sha}^..${sha}`]);
177
194
  changedFiles = diffSummary.files.map(f => f.file);
@@ -197,7 +214,7 @@ async function getPRMRDiff(repoRoot, sourceBranch, targetBranch) {
197
214
  }
198
215
  // Get diff between target and source (cumulative diff)
199
216
  // Format: git diff target...source (three-dot notation finds common ancestor)
200
- const diff = await git.diff([`${targetBranch}...${sourceBranch}`]);
217
+ const diff = await git.diff([`${targetBranch}...${sourceBranch}`, '-U200']);
201
218
  // Get list of changed files
202
219
  const diffSummary = await git.diffSummary([`${targetBranch}...${sourceBranch}`]);
203
220
  const changedFiles = diffSummary.files.map(f => f.file);
package/dist/index.js CHANGED
@@ -61,7 +61,7 @@ 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 || (process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : 'http://localhost:3000'))
64
+ .option('--api-url <url>', 'Threadline server URL', process.env.THREADLINE_API_URL || 'https://devthreadline.com')
65
65
  .option('--full', 'Show all results (compliant, attention, not_relevant). Default: only attention items')
66
66
  .option('--branch <name>', 'Review all commits in branch vs base (e.g., --branch feature/new-feature)')
67
67
  .option('--commit <ref>', 'Review specific commit. Accepts commit SHA or git reference (e.g., HEAD, HEAD~1, abc123). Example: --commit HEAD')
@@ -22,12 +22,14 @@ function getAutoReviewTarget() {
22
22
  const targetBranch = process.env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME;
23
23
  const sourceBranch = process.env.CI_MERGE_REQUEST_SOURCE_BRANCH_NAME;
24
24
  const mrNumber = process.env.CI_MERGE_REQUEST_IID;
25
+ const mrTitle = process.env.CI_MERGE_REQUEST_TITLE; // Reliable GitLab CI env var
25
26
  if (targetBranch && sourceBranch && mrNumber) {
26
27
  return {
27
28
  type: 'mr',
28
29
  value: mrNumber,
29
30
  sourceBranch,
30
- targetBranch
31
+ targetBranch,
32
+ prTitle: mrTitle || undefined // Only include if present
31
33
  };
32
34
  }
33
35
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "threadlines",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "description": "Threadline CLI - AI-powered linter based on your natural language documentation",
5
5
  "main": "dist/index.js",
6
6
  "bin": {