claude-teammate 0.1.259 → 0.1.261
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/repo.js +48 -16
- package/src/worker/jira-issue-workflow.js +4 -0
package/package.json
CHANGED
package/src/repo.js
CHANGED
|
@@ -8,6 +8,10 @@ import { buildGitEnvForRepoUrl, parseGitHubRepoUrl, parseRepoUrl } from "./forge
|
|
|
8
8
|
// tasks from racing to create the same worktree for the same branch.
|
|
9
9
|
const worktreeLocks = new Map();
|
|
10
10
|
|
|
11
|
+
// In-process lock: maps checkoutPath → Promise to prevent concurrent git clones
|
|
12
|
+
// to the same directory (race condition when two issues share the same repo).
|
|
13
|
+
const cloneInProgress = new Map();
|
|
14
|
+
|
|
11
15
|
const execFileAsync = promisify(execFile);
|
|
12
16
|
|
|
13
17
|
export class RepoCheckoutNotReadyError extends Error {
|
|
@@ -37,14 +41,28 @@ export async function ensureLocalRepo(repoUrl, reposDir) {
|
|
|
37
41
|
await forceRemoveCheckout(checkoutPath);
|
|
38
42
|
}
|
|
39
43
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
if (cloneInProgress.has(checkoutPath)) {
|
|
45
|
+
await cloneInProgress.get(checkoutPath);
|
|
46
|
+
return checkoutPath;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const clonePromise = (async () => {
|
|
50
|
+
await mkdir(path.dirname(checkoutPath), { recursive: true });
|
|
51
|
+
await execFileAsync("git", ["clone", repo.cloneUrl, checkoutPath], {
|
|
52
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
53
|
+
env: buildGitEnvForRepoUrl(repo.cloneUrl)
|
|
54
|
+
}).catch(async (err) => {
|
|
55
|
+
await forceRemoveCheckout(checkoutPath).catch(() => {});
|
|
56
|
+
throw err;
|
|
57
|
+
});
|
|
58
|
+
})();
|
|
59
|
+
|
|
60
|
+
cloneInProgress.set(checkoutPath, clonePromise);
|
|
61
|
+
try {
|
|
62
|
+
await clonePromise;
|
|
63
|
+
} finally {
|
|
64
|
+
cloneInProgress.delete(checkoutPath);
|
|
65
|
+
}
|
|
48
66
|
|
|
49
67
|
return checkoutPath;
|
|
50
68
|
}
|
|
@@ -79,14 +97,28 @@ export async function ensureReviewRepo(repoUrl, reviewReposDir) {
|
|
|
79
97
|
await forceRemoveCheckout(checkoutPath);
|
|
80
98
|
}
|
|
81
99
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
100
|
+
if (cloneInProgress.has(checkoutPath)) {
|
|
101
|
+
await cloneInProgress.get(checkoutPath);
|
|
102
|
+
return checkoutPath;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const clonePromise = (async () => {
|
|
106
|
+
await mkdir(path.dirname(checkoutPath), { recursive: true });
|
|
107
|
+
await execFileAsync("git", ["clone", repo.cloneUrl, checkoutPath], {
|
|
108
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
109
|
+
env: buildGitEnvForRepoUrl(repo.cloneUrl)
|
|
110
|
+
}).catch(async (err) => {
|
|
111
|
+
await forceRemoveCheckout(checkoutPath).catch(() => {});
|
|
112
|
+
throw err;
|
|
113
|
+
});
|
|
114
|
+
})();
|
|
115
|
+
|
|
116
|
+
cloneInProgress.set(checkoutPath, clonePromise);
|
|
117
|
+
try {
|
|
118
|
+
await clonePromise;
|
|
119
|
+
} finally {
|
|
120
|
+
cloneInProgress.delete(checkoutPath);
|
|
121
|
+
}
|
|
90
122
|
|
|
91
123
|
return checkoutPath;
|
|
92
124
|
}
|
|
@@ -369,6 +369,8 @@ export async function processJiraIssue({
|
|
|
369
369
|
|
|
370
370
|
if (repoCheckoutUpdated) {
|
|
371
371
|
await saveProgress("Repository ready. Analyzing requirements...");
|
|
372
|
+
epicMemory.repos = liveRepos;
|
|
373
|
+
epicMemory = await services.saveEpicMemory(epicMemoryRecord.filePath, detail, epicMemory);
|
|
372
374
|
}
|
|
373
375
|
|
|
374
376
|
const linkedSource = await services.fetchLinkedForgeState({
|
|
@@ -522,6 +524,8 @@ export async function processJiraIssue({
|
|
|
522
524
|
|
|
523
525
|
if (claudeResult.decision === "needs_clarification") {
|
|
524
526
|
issueMemory.progress_comment_id = null;
|
|
527
|
+
issueMemory.code_change_input_id = latestInput.id;
|
|
528
|
+
issueMemory = await services.saveIssueMemory(issueMemoryRecord.filePath, detail, issueMemory);
|
|
525
529
|
await ensureJiraComment(detail, jira, botUser, formatClarificationQuestions(claudeResult.questions));
|
|
526
530
|
await logger.info("Clarification requested from Jira", {
|
|
527
531
|
issue: detail.key,
|