claude-teammate 0.1.13 → 0.1.14
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 +52 -3
- package/src/repo.js +32 -1
package/package.json
CHANGED
package/src/commands/worker.js
CHANGED
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
listMissingRepoPaths,
|
|
33
33
|
parseGitHubRepoUrl,
|
|
34
34
|
prepareRepoForBranch,
|
|
35
|
+
RepoCheckoutNotReadyError,
|
|
35
36
|
validateOrEnsureLocalRepo
|
|
36
37
|
} from "../repo.js";
|
|
37
38
|
import {
|
|
@@ -206,7 +207,18 @@ export async function runWorkerCommand({ projectRoot }) {
|
|
|
206
207
|
let trackedIssueCount = 0;
|
|
207
208
|
|
|
208
209
|
for (const repo of repos) {
|
|
209
|
-
|
|
210
|
+
try {
|
|
211
|
+
repo.local_path = await validateOrEnsureLocalRepo(repo.url, runtimePaths.reposDir, repo.local_path);
|
|
212
|
+
} catch (error) {
|
|
213
|
+
if (isRepoCheckoutNotReadyError(error)) {
|
|
214
|
+
await logger.info("Skipping GitHub repo until checkout is ready", {
|
|
215
|
+
repo: repo.url,
|
|
216
|
+
localPath: error.localPath || repo.local_path
|
|
217
|
+
});
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
throw error;
|
|
221
|
+
}
|
|
210
222
|
const issues = await github.listIssues(repo.url);
|
|
211
223
|
const botIssues = issues.filter((issue) => isGitHubBotAuthor(issue.author, githubBotUser));
|
|
212
224
|
trackedIssueCount += botIssues.length;
|
|
@@ -258,7 +270,18 @@ export async function runWorkerCommand({ projectRoot }) {
|
|
|
258
270
|
let trackedPrCount = 0;
|
|
259
271
|
|
|
260
272
|
for (const repo of repos) {
|
|
261
|
-
|
|
273
|
+
try {
|
|
274
|
+
repo.local_path = await validateOrEnsureLocalRepo(repo.url, runtimePaths.reposDir, repo.local_path);
|
|
275
|
+
} catch (error) {
|
|
276
|
+
if (isRepoCheckoutNotReadyError(error)) {
|
|
277
|
+
await logger.info("Skipping draft PR repo until checkout is ready", {
|
|
278
|
+
repo: repo.url,
|
|
279
|
+
localPath: error.localPath || repo.local_path
|
|
280
|
+
});
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
throw error;
|
|
284
|
+
}
|
|
262
285
|
|
|
263
286
|
const pullRequests = await github.listPullRequests(repo.url);
|
|
264
287
|
const botPullRequests = pullRequests.filter(
|
|
@@ -403,7 +426,22 @@ async function processJiraIssue({ issue, jira, github, botUser, config, projectR
|
|
|
403
426
|
|
|
404
427
|
let repoCheckoutUpdated = false;
|
|
405
428
|
for (const repo of epicMemory.repos) {
|
|
406
|
-
|
|
429
|
+
let validatedLocalPath;
|
|
430
|
+
try {
|
|
431
|
+
validatedLocalPath = await validateOrEnsureLocalRepo(repo.url, runtimePaths.reposDir, repo.local_path);
|
|
432
|
+
} catch (error) {
|
|
433
|
+
if (isRepoCheckoutNotReadyError(error)) {
|
|
434
|
+
issueMemory.last_error = `Repository checkout is not ready yet for ${repo.url}. The worker will retry automatically.`;
|
|
435
|
+
issueMemory = await saveIssueMemory(issueMemoryRecord.filePath, detail, issueMemory);
|
|
436
|
+
await logger.info("Skipping Jira issue until checkout is ready", {
|
|
437
|
+
issue: detail.key,
|
|
438
|
+
repo: repo.url,
|
|
439
|
+
localPath: error.localPath || repo.local_path
|
|
440
|
+
});
|
|
441
|
+
return buildIssueState(detail, epicMemory, issueMemory, null, issueMemory.last_error);
|
|
442
|
+
}
|
|
443
|
+
throw error;
|
|
444
|
+
}
|
|
407
445
|
if (validatedLocalPath !== repo.local_path) {
|
|
408
446
|
repo.local_path = validatedLocalPath;
|
|
409
447
|
repoCheckoutUpdated = true;
|
|
@@ -2234,6 +2272,17 @@ function normalizeRepoAlias(value) {
|
|
|
2234
2272
|
return String(value || "").trim().toLowerCase();
|
|
2235
2273
|
}
|
|
2236
2274
|
|
|
2275
|
+
function isRepoCheckoutNotReadyError(error) {
|
|
2276
|
+
return Boolean(
|
|
2277
|
+
error &&
|
|
2278
|
+
typeof error === "object" &&
|
|
2279
|
+
(
|
|
2280
|
+
error instanceof RepoCheckoutNotReadyError ||
|
|
2281
|
+
error.code === "REPO_CHECKOUT_NOT_READY"
|
|
2282
|
+
)
|
|
2283
|
+
);
|
|
2284
|
+
}
|
|
2285
|
+
|
|
2237
2286
|
function normalizeRepoRelativePath(value) {
|
|
2238
2287
|
const normalized = String(value || "").trim().replace(/^\/+/u, "").replace(/\/+$/u, "");
|
|
2239
2288
|
if (!normalized || normalized.startsWith("http://") || normalized.startsWith("https://")) {
|
package/src/repo.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { access, mkdir } from "node:fs/promises";
|
|
1
|
+
import { access, mkdir, readdir } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { execFile } from "node:child_process";
|
|
4
4
|
import process from "node:process";
|
|
@@ -6,6 +6,16 @@ import { promisify } from "node:util";
|
|
|
6
6
|
|
|
7
7
|
const execFileAsync = promisify(execFile);
|
|
8
8
|
|
|
9
|
+
export class RepoCheckoutNotReadyError extends Error {
|
|
10
|
+
constructor(message, details = {}) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = "RepoCheckoutNotReadyError";
|
|
13
|
+
this.code = "REPO_CHECKOUT_NOT_READY";
|
|
14
|
+
this.repoUrl = details.repoUrl || "";
|
|
15
|
+
this.localPath = details.localPath || "";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
9
19
|
export async function ensureLocalRepo(repoUrl, reposDir) {
|
|
10
20
|
const repo = parseGitHubRepoUrl(repoUrl);
|
|
11
21
|
const checkoutPath = path.join(reposDir, repo.owner, repo.name);
|
|
@@ -28,6 +38,19 @@ export async function validateOrEnsureLocalRepo(repoUrl, reposDir, localPath = "
|
|
|
28
38
|
return candidatePath;
|
|
29
39
|
}
|
|
30
40
|
|
|
41
|
+
if (candidatePath && await pathExists(candidatePath)) {
|
|
42
|
+
const entries = await safeReadDir(candidatePath);
|
|
43
|
+
if (entries.length > 0) {
|
|
44
|
+
throw new RepoCheckoutNotReadyError(
|
|
45
|
+
`Repository checkout is not ready yet at ${candidatePath}.`,
|
|
46
|
+
{
|
|
47
|
+
repoUrl,
|
|
48
|
+
localPath: candidatePath
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
31
54
|
return ensureLocalRepo(repoUrl, reposDir);
|
|
32
55
|
}
|
|
33
56
|
|
|
@@ -114,6 +137,14 @@ async function pathExists(targetPath) {
|
|
|
114
137
|
}
|
|
115
138
|
}
|
|
116
139
|
|
|
140
|
+
async function safeReadDir(targetPath) {
|
|
141
|
+
try {
|
|
142
|
+
return await readdir(targetPath);
|
|
143
|
+
} catch {
|
|
144
|
+
return [];
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
117
148
|
async function isUsableGitCheckout(repoPath) {
|
|
118
149
|
if (!repoPath) {
|
|
119
150
|
return false;
|