claude-teammate 0.1.34 → 0.1.36

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-teammate",
3
- "version": "0.1.34",
3
+ "version": "0.1.36",
4
4
  "description": "CLI bootstrapper for Claude Teammate.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -27,7 +27,7 @@ import {
27
27
  } from "../memory.js";
28
28
  import {
29
29
  commitAndPushRepoChanges,
30
- ensureBranchFromMain,
30
+ ensureBranchFromDefault,
31
31
  hasUsableGitCheckout,
32
32
  listMissingRepoPaths,
33
33
  parseGitHubRepoUrl,
@@ -612,6 +612,25 @@ async function processGitHubIssue({ repo, issue, projectRoot, github, githubBotU
612
612
  return buildGitHubIssueState(detail, githubIssueMemory, null);
613
613
  }
614
614
 
615
+ if (hasPlusOneReaction(latestComment)) {
616
+ return buildGitHubIssueState(detail, githubIssueMemory, null);
617
+ }
618
+
619
+ try {
620
+ const isMember = await github.isRepoCollaborator(repo.url, latestComment.author.login);
621
+ if (!isMember) {
622
+ await github.createIssueCommentReaction(repo.url, latestComment.id, "+1");
623
+ return buildGitHubIssueState(detail, githubIssueMemory, null);
624
+ }
625
+ } catch (error) {
626
+ await logger.error("Failed to check GitHub collaborator status", {
627
+ repo: repo.url,
628
+ author: latestComment.author.login,
629
+ error: String(error)
630
+ });
631
+ return buildGitHubIssueState(detail, githubIssueMemory, null);
632
+ }
633
+
615
634
  const approvalComment = isApprovalComment(latestComment.body);
616
635
 
617
636
  if (approvalComment) {
@@ -658,12 +677,13 @@ async function processGitHubIssue({ repo, issue, projectRoot, github, githubBotU
658
677
  return buildGitHubIssueState(detail, githubIssueMemory, "blocked");
659
678
  }
660
679
 
661
- await ensureBranchFromMain(githubIssueMemory.local_path, nextBranchName);
680
+ const defaultBranch = await github.getDefaultBranch(githubIssueMemory.repo_url);
681
+ await ensureBranchFromDefault(githubIssueMemory.local_path, nextBranchName, defaultBranch);
662
682
  const pullRequest = await github.createPullRequest(githubIssueMemory.repo_url, {
663
683
  title: detail.title,
664
684
  body: buildInitialPullRequestBody(detail.number, detail.body),
665
685
  head: nextBranchName,
666
- base: "main",
686
+ base: defaultBranch,
667
687
  draft: true
668
688
  });
669
689
  githubIssueMemory.pr_url = pullRequest.url;
@@ -836,6 +856,25 @@ async function processTrackedPullRequest({ projectRoot, repo, pullRequest, githu
836
856
  return buildDraftPrState(detail, currentStatus, null);
837
857
  }
838
858
 
859
+ if (hasPlusOneReaction(latestComment)) {
860
+ return buildDraftPrState(detail, currentStatus, null);
861
+ }
862
+
863
+ try {
864
+ const isMember = await github.isRepoCollaborator(repo.url, latestComment.author.login);
865
+ if (!isMember) {
866
+ await github.createIssueCommentReaction(repo.url, latestComment.id, "+1");
867
+ return buildDraftPrState(detail, currentStatus, null);
868
+ }
869
+ } catch (error) {
870
+ await logger.error("Failed to check GitHub collaborator status", {
871
+ repo: repo.url,
872
+ author: latestComment.author.login,
873
+ error: String(error)
874
+ });
875
+ return buildDraftPrState(detail, currentStatus, null);
876
+ }
877
+
839
878
  const commentReviewRepoAccess = await buildPullRequestRepoAccessPlan({
840
879
  repo,
841
880
  pullRequestBody: detail.body || "",
@@ -1681,6 +1720,10 @@ function hasEyesReaction(comment) {
1681
1720
  return Number(comment?.reactions?.eyes ?? 0) > 0;
1682
1721
  }
1683
1722
 
1723
+ export function hasPlusOneReaction(comment) {
1724
+ return Number(comment?.reactions?.plusOne ?? 0) > 0;
1725
+ }
1726
+
1684
1727
  function formatClarificationQuestions(questions) {
1685
1728
  const cleanedQuestions = questions.filter(Boolean);
1686
1729
  if (cleanedQuestions.length === 0) {
package/src/github.js CHANGED
@@ -181,6 +181,28 @@ export function createGitHubClient(config) {
181
181
  );
182
182
  },
183
183
 
184
+ async isRepoCollaborator(repoUrl, username) {
185
+ const repo = parseGitHubRepoUrl(repoUrl);
186
+ const response = await fetch(
187
+ `https://api.github.com/repos/${repo.owner}/${repo.name}/collaborators/${encodeURIComponent(username)}`,
188
+ {
189
+ headers: {
190
+ Accept: "application/vnd.github+json",
191
+ Authorization: `Bearer ${config.GITHUB_PAT}`,
192
+ "User-Agent": "claude-teammate"
193
+ }
194
+ }
195
+ );
196
+ if (response.status === 204) {
197
+ return true;
198
+ }
199
+ if (response.status === 404) {
200
+ return false;
201
+ }
202
+ const body = await response.text();
203
+ throw new Error(`GitHub collaborator check failed with status ${response.status}: ${body}`);
204
+ },
205
+
184
206
  async updatePullRequest(repoUrl, pullNumber, updates) {
185
207
  const repo = parseGitHubRepoUrl(repoUrl);
186
208
  const payload = await requestGitHub(
@@ -257,6 +279,17 @@ export function createGitHubClient(config) {
257
279
  };
258
280
  },
259
281
 
282
+ async getDefaultBranch(repoUrl) {
283
+ const repo = parseGitHubRepoUrl(repoUrl);
284
+ const payload = await requestGitHub(
285
+ `https://api.github.com/repos/${repo.owner}/${repo.name}`,
286
+ config,
287
+ { method: "GET" },
288
+ repo
289
+ );
290
+ return payload.default_branch;
291
+ },
292
+
260
293
  async createPullRequest(repoUrl, pullRequest) {
261
294
  const repo = parseGitHubRepoUrl(repoUrl);
262
295
  const payload = await requestGitHub(
@@ -355,7 +388,8 @@ function mapGitHubComment(payload) {
355
388
  createdAt: payload.created_at ?? null,
356
389
  updatedAt: payload.updated_at ?? null,
357
390
  reactions: {
358
- eyes: Number(payload.reactions?.eyes ?? 0)
391
+ eyes: Number(payload.reactions?.eyes ?? 0),
392
+ plusOne: Number(payload.reactions?.["+1"] ?? 0)
359
393
  },
360
394
  author: {
361
395
  login: payload.user?.login ?? null,
package/src/repo.js CHANGED
@@ -54,18 +54,18 @@ export async function validateOrEnsureLocalRepo(repoUrl, reposDir, localPath = "
54
54
  return ensureLocalRepo(repoUrl, reposDir);
55
55
  }
56
56
 
57
- export async function ensureBranchFromMain(repoPath, branchName) {
57
+ export async function ensureBranchFromDefault(repoPath, branchName, baseBranch) {
58
58
  try {
59
- await execGit(repoPath, ["fetch", "origin", "main", "--prune"]);
59
+ await execGit(repoPath, ["fetch", "origin", baseBranch, "--prune"]);
60
60
  } catch (error) {
61
- if (!isMissingRemoteMainError(error)) {
61
+ if (!isMissingRemoteBranchError(error)) {
62
62
  throw error;
63
63
  }
64
64
 
65
- await initializeRemoteMainBranch(repoPath);
65
+ await initializeRemoteDefaultBranch(repoPath, baseBranch);
66
66
  }
67
67
 
68
- await execGit(repoPath, ["checkout", "-B", branchName, "origin/main"]);
68
+ await execGit(repoPath, ["checkout", "-B", branchName, `origin/${baseBranch}`]);
69
69
  await execGit(repoPath, [
70
70
  "-c",
71
71
  "user.name=Claude Teammate",
@@ -79,6 +79,10 @@ export async function ensureBranchFromMain(repoPath, branchName) {
79
79
  await execGit(repoPath, ["push", "-u", "origin", branchName]);
80
80
  }
81
81
 
82
+ export async function ensureBranchFromMain(repoPath, branchName) {
83
+ return ensureBranchFromDefault(repoPath, branchName, "main");
84
+ }
85
+
82
86
  export async function prepareRepoForBranch(repoPath, branchName) {
83
87
  await execGit(repoPath, ["fetch", "origin", branchName, "--prune"]);
84
88
  await execGit(repoPath, ["reset", "--hard"]);
@@ -211,8 +215,8 @@ async function branchHasChangesAgainstMain(repoPath) {
211
215
  return Number.isFinite(count) && count > 0;
212
216
  }
213
217
 
214
- async function initializeRemoteMainBranch(repoPath) {
215
- await execGit(repoPath, ["checkout", "--orphan", "main"]);
218
+ async function initializeRemoteDefaultBranch(repoPath, baseBranch) {
219
+ await execGit(repoPath, ["checkout", "--orphan", baseBranch]);
216
220
  await execGit(repoPath, [
217
221
  "-c",
218
222
  "user.name=Claude Teammate",
@@ -221,9 +225,9 @@ async function initializeRemoteMainBranch(repoPath) {
221
225
  "commit",
222
226
  "--allow-empty",
223
227
  "-m",
224
- "Initialize main"
228
+ `Initialize ${baseBranch}`
225
229
  ]);
226
- await execGit(repoPath, ["push", "-u", "origin", "main"]);
230
+ await execGit(repoPath, ["push", "-u", "origin", baseBranch]);
227
231
  }
228
232
 
229
233
  function formatGitExecError(error) {
@@ -241,9 +245,9 @@ function formatGitExecError(error) {
241
245
  return new Error(`${message}\n${detail}`);
242
246
  }
243
247
 
244
- function isMissingRemoteMainError(error) {
248
+ function isMissingRemoteBranchError(error) {
245
249
  const message = error instanceof Error ? error.message : String(error);
246
- return /couldn't find remote ref main/u.test(message);
250
+ return /couldn't find remote ref /u.test(message);
247
251
  }
248
252
 
249
253
  function parseGitHubPath(rawPath) {