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 +1 -1
- package/src/commands/worker.js +46 -3
- package/src/github.js +35 -1
- package/src/repo.js +15 -11
package/package.json
CHANGED
package/src/commands/worker.js
CHANGED
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
} from "../memory.js";
|
|
28
28
|
import {
|
|
29
29
|
commitAndPushRepoChanges,
|
|
30
|
-
|
|
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
|
|
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:
|
|
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
|
|
57
|
+
export async function ensureBranchFromDefault(repoPath, branchName, baseBranch) {
|
|
58
58
|
try {
|
|
59
|
-
await execGit(repoPath, ["fetch", "origin",
|
|
59
|
+
await execGit(repoPath, ["fetch", "origin", baseBranch, "--prune"]);
|
|
60
60
|
} catch (error) {
|
|
61
|
-
if (!
|
|
61
|
+
if (!isMissingRemoteBranchError(error)) {
|
|
62
62
|
throw error;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
await
|
|
65
|
+
await initializeRemoteDefaultBranch(repoPath, baseBranch);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
await execGit(repoPath, ["checkout", "-B", branchName,
|
|
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
|
|
215
|
-
await execGit(repoPath, ["checkout", "--orphan",
|
|
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
|
-
|
|
228
|
+
`Initialize ${baseBranch}`
|
|
225
229
|
]);
|
|
226
|
-
await execGit(repoPath, ["push", "-u", "origin",
|
|
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
|
|
248
|
+
function isMissingRemoteBranchError(error) {
|
|
245
249
|
const message = error instanceof Error ? error.message : String(error);
|
|
246
|
-
return /couldn't find remote ref
|
|
250
|
+
return /couldn't find remote ref /u.test(message);
|
|
247
251
|
}
|
|
248
252
|
|
|
249
253
|
function parseGitHubPath(rawPath) {
|