claude-teammate 0.1.255 → 0.1.256
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
package/src/memory.js
CHANGED
|
@@ -458,7 +458,10 @@ function uniqueGitHubIssues(githubIssues) {
|
|
|
458
458
|
continue;
|
|
459
459
|
}
|
|
460
460
|
|
|
461
|
-
const key =
|
|
461
|
+
const key =
|
|
462
|
+
githubIssue.repo_url && githubIssue.number
|
|
463
|
+
? `${githubIssue.repo_url}#${githubIssue.number}`
|
|
464
|
+
: githubIssue.url || githubIssue.repo_url;
|
|
462
465
|
if (!key) {
|
|
463
466
|
continue;
|
|
464
467
|
}
|
|
@@ -325,23 +325,38 @@ export async function processJiraIssue({
|
|
|
325
325
|
}
|
|
326
326
|
|
|
327
327
|
let repoCheckoutUpdated = false;
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
328
|
+
const repoValidationOutcomes = await Promise.allSettled(
|
|
329
|
+
liveRepos.map((repo) =>
|
|
330
|
+
services.validateOrEnsureLocalRepo(repo.url, runtimePaths.reposDir, repo.local_path).then(
|
|
331
|
+
(validatedLocalPath) => ({ repo, validatedLocalPath }),
|
|
332
|
+
(error) => {
|
|
333
|
+
error._repo = repo;
|
|
334
|
+
throw error;
|
|
335
|
+
}
|
|
336
|
+
)
|
|
337
|
+
)
|
|
338
|
+
);
|
|
339
|
+
|
|
340
|
+
for (const outcome of repoValidationOutcomes) {
|
|
341
|
+
if (outcome.status === "rejected") {
|
|
342
|
+
const error = outcome.reason;
|
|
343
|
+
const failedRepo = error._repo ?? liveRepos[0];
|
|
333
344
|
if (isRepoCheckoutNotReadyError(error)) {
|
|
334
|
-
issueMemory.last_error = `Repository checkout is not ready yet for ${
|
|
345
|
+
issueMemory.last_error = `Repository checkout is not ready yet for ${failedRepo.url}. The worker will retry automatically.`;
|
|
335
346
|
issueMemory = await services.saveIssueMemory(issueMemoryRecord.filePath, detail, issueMemory);
|
|
336
347
|
await logger.info("Skipping Jira issue until checkout is ready", {
|
|
337
348
|
issue: detail.key,
|
|
338
|
-
repo:
|
|
339
|
-
localPath: error.localPath ||
|
|
349
|
+
repo: failedRepo.url,
|
|
350
|
+
localPath: error.localPath || failedRepo.local_path
|
|
340
351
|
});
|
|
341
352
|
return buildIssueState(detail, { repos: liveRepos }, issueMemory, null, issueMemory.last_error);
|
|
342
353
|
}
|
|
343
354
|
throw error;
|
|
344
355
|
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
for (const outcome of repoValidationOutcomes) {
|
|
359
|
+
const { repo, validatedLocalPath } = outcome.value;
|
|
345
360
|
if (validatedLocalPath !== repo.local_path) {
|
|
346
361
|
repo.local_path = validatedLocalPath;
|
|
347
362
|
repoCheckoutUpdated = true;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getForgeBotUserForRepo } from "../forge-sync.js";
|
|
2
2
|
import { processReviewSuggestionFeedback as defaultProcessReviewSuggestionFeedback } from "../review-suggestion.js";
|
|
3
3
|
import { pollStuckTasks } from "../stuck-tasks.js";
|
|
4
|
+
import { markWorkQueueItemRunning, queueWorkQueueItem, removeWorkQueueItem } from "../worker-state.js";
|
|
4
5
|
import { loadKnownRepos } from "./helpers.js";
|
|
5
6
|
|
|
6
7
|
export function createReviewPullRequestDiscussionPoller({
|
|
@@ -20,6 +21,17 @@ export function createReviewPullRequestDiscussionPoller({
|
|
|
20
21
|
return `review-discussion:${repoUrl}!${prNumber}`;
|
|
21
22
|
}
|
|
22
23
|
|
|
24
|
+
function buildWorkQueueItem(pr) {
|
|
25
|
+
return {
|
|
26
|
+
id: buildTaskId(pr.repoUrl, pr.number),
|
|
27
|
+
kind: "review_discussion",
|
|
28
|
+
label: `${String(pr?.repoUrl || "").trim()}!${String(pr?.number || "").trim()}`,
|
|
29
|
+
title: String(pr?.title || "").trim(),
|
|
30
|
+
repoUrl: String(pr?.repoUrl || "").trim(),
|
|
31
|
+
pullRequestNumber: String(pr?.number || "").trim()
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
23
35
|
return async function runReviewPullRequestDiscussionPoll() {
|
|
24
36
|
const repos = await loadKnownRepos(projectRoot, forgeRegistry);
|
|
25
37
|
const repoUrls = repos.map((repo) => repo.url);
|
|
@@ -63,9 +75,14 @@ export function createReviewPullRequestDiscussionPoller({
|
|
|
63
75
|
continue;
|
|
64
76
|
}
|
|
65
77
|
inFlight.add(taskId);
|
|
78
|
+
const workQueueItem = buildWorkQueueItem(pr);
|
|
79
|
+
queueWorkQueueItem(state, workQueueItem);
|
|
80
|
+
await persistState();
|
|
66
81
|
|
|
67
82
|
void (async () => {
|
|
68
83
|
const release = await pool.acquire();
|
|
84
|
+
markWorkQueueItemRunning(state, workQueueItem);
|
|
85
|
+
await persistState();
|
|
69
86
|
try {
|
|
70
87
|
const repo = repos.find((r) => r.url === pr.repoUrl);
|
|
71
88
|
await processReviewSuggestionFeedback({
|
|
@@ -88,6 +105,8 @@ export function createReviewPullRequestDiscussionPoller({
|
|
|
88
105
|
});
|
|
89
106
|
} finally {
|
|
90
107
|
inFlight.delete(taskId);
|
|
108
|
+
removeWorkQueueItem(state, workQueueItem.id);
|
|
109
|
+
await persistState();
|
|
91
110
|
release();
|
|
92
111
|
}
|
|
93
112
|
})();
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import { listIssueMemoryRecords } from "../../memory.js";
|
|
2
|
-
import {
|
|
3
|
-
findIssueMemoryByGitHubIssue,
|
|
4
|
-
getForgeBotUserForRepo,
|
|
5
|
-
getLatestGitHubComment,
|
|
6
|
-
isForgeBotAuthor
|
|
7
|
-
} from "../forge-sync.js";
|
|
2
|
+
import { getForgeBotUserForRepo, getLatestGitHubComment, isForgeBotAuthor } from "../forge-sync.js";
|
|
8
3
|
import { checkCommentAuthorIsMember, hasEyesReaction, hasPlusOneReaction, isApprovalComment } from "../pull-request.js";
|
|
9
4
|
import { normalizeRepoIdentity } from "../repo-utils.js";
|
|
10
5
|
import { buildIssueQueueId, buildQueuedTrackedIssueState, reconcileQueueEntry } from "../state-builders.js";
|
|
@@ -60,9 +55,9 @@ export function createTrackedIssuePoller({
|
|
|
60
55
|
}
|
|
61
56
|
|
|
62
57
|
async function getDispatchDecision({ issue, repo, provider, botUser, issueMemoryIndex }) {
|
|
63
|
-
const issueMemoryRecord =
|
|
64
|
-
|
|
65
|
-
|
|
58
|
+
const issueMemoryRecord = issueMemoryIndex.get(
|
|
59
|
+
`${normalizeRepoIdentity(repo.url || "")}#${String(issue.number || "").trim()}`
|
|
60
|
+
);
|
|
66
61
|
if (!issueMemoryRecord) {
|
|
67
62
|
await logger.info("GitHub issue has no linked Jira memory, not queueing for work", {
|
|
68
63
|
issue: issue.number,
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { isClaudeCliError, runClaudeRevisionPrompt } from "../claude.js";
|
|
4
4
|
import { toErrorMessage } from "./utils.js";
|
|
5
5
|
|
|
6
6
|
const FILE_CONTEXT_LINES = 20;
|
|
7
7
|
|
|
8
|
-
function readFileContext(repoPath, filePath, targetLine) {
|
|
8
|
+
async function readFileContext(repoPath, filePath, targetLine) {
|
|
9
9
|
if (!repoPath || !filePath) {
|
|
10
10
|
return "";
|
|
11
11
|
}
|
|
12
12
|
try {
|
|
13
13
|
const absPath = path.join(repoPath, filePath);
|
|
14
|
-
const content =
|
|
14
|
+
const content = await readFile(absPath, "utf8");
|
|
15
15
|
const lines = content.split("\n");
|
|
16
16
|
const start = Math.max(0, targetLine - FILE_CONTEXT_LINES - 1);
|
|
17
17
|
const end = Math.min(lines.length, targetLine + FILE_CONTEXT_LINES);
|
|
@@ -60,7 +60,7 @@ export async function processReviewSuggestionFeedback({
|
|
|
60
60
|
const taskId = `suggestionRevision:${repoUrl}!${prNumber}`;
|
|
61
61
|
|
|
62
62
|
for (const thread of threads) {
|
|
63
|
-
const fileContext = readFileContext(repoPath, thread.file, thread.line);
|
|
63
|
+
const fileContext = await readFileContext(repoPath, thread.file, thread.line);
|
|
64
64
|
let result;
|
|
65
65
|
try {
|
|
66
66
|
result = await runClaudeRevisionPromptFn({
|