@tarcisiopgs/lisa 1.31.0 → 1.32.0
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/README.md +8 -0
- package/dist/{chunk-45ZNECZ5.js → chunk-AAWXKEV7.js} +25 -1
- package/dist/{chunk-YTHUJQKB.js → chunk-K2ILRYXS.js} +1 -1
- package/dist/{chunk-RQTH257A.js → chunk-NHC3JG2C.js} +220 -1
- package/dist/{chunk-IQDRQXFK.js → chunk-R6D5VH65.js} +1 -1
- package/dist/{chunk-72DVXSHO.js → chunk-YMV4CBQE.js} +94 -1
- package/dist/{detection-PC7EMUHY.js → detection-H5QJR5XI.js} +2 -2
- package/dist/index.js +39 -10
- package/dist/{kanban-TXO3LZON.js → kanban-F27DQLKJ.js} +52 -13
- package/dist/{loop-INGME5Y3.js → loop-PXUNTCQS.js} +3 -3
- package/dist/{tui-bridge-KSE7MJDX.js → tui-bridge-WKKIHWJT.js} +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -49,6 +49,7 @@ If something fails — pre-push hooks, quota limits, stuck processes — Lisa ha
|
|
|
49
49
|
- **CI monitoring** — polls CI after PR creation, re-invokes the agent to fix failures automatically
|
|
50
50
|
- **Progress comments** — posts real-time status updates on issues as Lisa works through stages
|
|
51
51
|
- **Context enrichment** — greps for issue-related files and surfaces them in the agent prompt
|
|
52
|
+
- **PR reviewers & assignees** — auto-request reviews and assign PRs via config; `self` keyword resolves to the authenticated user
|
|
52
53
|
- **Self-healing** — orphan recovery on startup, push failure retry, stuck process detection
|
|
53
54
|
- **Guardrails** — past failures are injected into future prompts to avoid repeating mistakes
|
|
54
55
|
- **Project context** — auto-generates `.lisa/context.md` with your stack, conventions, and constraints
|
|
@@ -254,6 +255,13 @@ ci_monitor:
|
|
|
254
255
|
progress_comments:
|
|
255
256
|
enabled: true # post real-time status on issues
|
|
256
257
|
|
|
258
|
+
pr:
|
|
259
|
+
reviewers: # auto-request reviews on every PR
|
|
260
|
+
- octocat
|
|
261
|
+
- hubot
|
|
262
|
+
assignees: # auto-assign PRs ("self" = authenticated user)
|
|
263
|
+
- self
|
|
264
|
+
|
|
257
265
|
hooks:
|
|
258
266
|
before_run: "./scripts/setup.sh"
|
|
259
267
|
after_run: "./scripts/cleanup.sh"
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
appendPlatformAttribution,
|
|
6
6
|
appendPlatformProofOfWork,
|
|
7
7
|
appendPlatformSpecCompliance,
|
|
8
|
+
applyPrReviewersAndAssignees,
|
|
8
9
|
buildCompliancePrompt,
|
|
9
10
|
buildComplianceRecoveryPrompt,
|
|
10
11
|
buildContinuationPrompt,
|
|
@@ -29,7 +30,7 @@ import {
|
|
|
29
30
|
resolveModels,
|
|
30
31
|
runValidationCommands,
|
|
31
32
|
runWithFallback
|
|
32
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-NHC3JG2C.js";
|
|
33
34
|
import {
|
|
34
35
|
divider,
|
|
35
36
|
error,
|
|
@@ -192,6 +193,23 @@ function findConfigDir(startDir = process.cwd()) {
|
|
|
192
193
|
dir = parent;
|
|
193
194
|
}
|
|
194
195
|
}
|
|
196
|
+
var USERNAME_RE = /^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,38}$/;
|
|
197
|
+
function isValidPrUsername(s) {
|
|
198
|
+
return s === "self" || USERNAME_RE.test(s);
|
|
199
|
+
}
|
|
200
|
+
function isStringArray(v) {
|
|
201
|
+
return Array.isArray(v) && v.every((item) => typeof item === "string");
|
|
202
|
+
}
|
|
203
|
+
function parsePrConfig(raw) {
|
|
204
|
+
if (!raw) return void 0;
|
|
205
|
+
const reviewers = isStringArray(raw.reviewers) ? raw.reviewers.filter(isValidPrUsername) : void 0;
|
|
206
|
+
const assignees = isStringArray(raw.assignees) ? raw.assignees.filter(isValidPrUsername) : void 0;
|
|
207
|
+
if (!reviewers?.length && !assignees?.length) return void 0;
|
|
208
|
+
return {
|
|
209
|
+
reviewers: reviewers?.length ? reviewers : void 0,
|
|
210
|
+
assignees: assignees?.length ? assignees : void 0
|
|
211
|
+
};
|
|
212
|
+
}
|
|
195
213
|
function loadConfig(cwd = process.cwd()) {
|
|
196
214
|
const configPath = getConfigPath(cwd);
|
|
197
215
|
if (!existsSync(configPath)) {
|
|
@@ -234,6 +252,7 @@ function loadConfig(cwd = process.cwd()) {
|
|
|
234
252
|
const rawCiMonitor = parsed.ci_monitor;
|
|
235
253
|
const rawSpecCompliance = parsed.spec_compliance;
|
|
236
254
|
const rawProgress = parsed.progress_comments;
|
|
255
|
+
const rawPr = parsed.pr;
|
|
237
256
|
const config = {
|
|
238
257
|
...DEFAULT_CONFIG,
|
|
239
258
|
...parsedWithoutLogs,
|
|
@@ -279,6 +298,7 @@ function loadConfig(cwd = process.cwd()) {
|
|
|
279
298
|
block_on_failure: rawSpecCompliance.block_on_failure
|
|
280
299
|
} : void 0,
|
|
281
300
|
progress_comments: rawProgress ? { enabled: rawProgress.enabled ?? false } : void 0,
|
|
301
|
+
pr: parsePrConfig(rawPr),
|
|
282
302
|
provider_options: {
|
|
283
303
|
...DEFAULT_CONFIG.provider_options || {},
|
|
284
304
|
...parsed.provider_options ?? {}
|
|
@@ -2577,6 +2597,7 @@ ${contResult.output}
|
|
|
2577
2597
|
await executeHook("before_remove", config.hooks, worktreePath, hookEnv);
|
|
2578
2598
|
await cleanupWorktree(repoPath, worktreePath);
|
|
2579
2599
|
await appendPlatformAttribution(prUrl, result.providerUsed, config.platform);
|
|
2600
|
+
await applyPrReviewersAndAssignees(prUrl, config.pr, config.platform);
|
|
2580
2601
|
ok(`Step ${stepNum} complete: ${repoPath} \u2014 PR: ${prUrl}`);
|
|
2581
2602
|
return {
|
|
2582
2603
|
success: true,
|
|
@@ -2746,6 +2767,7 @@ async function runNativeWorktreeSession(config, issue, logFile, session, models,
|
|
|
2746
2767
|
}
|
|
2747
2768
|
ok(`PR created by provider: ${prUrl}`);
|
|
2748
2769
|
await appendPlatformAttribution(prUrl, result.providerUsed, config.platform);
|
|
2770
|
+
await applyPrReviewersAndAssignees(prUrl, config.pr, config.platform);
|
|
2749
2771
|
if (isCiMonitorEnabled(config.ci_monitor)) {
|
|
2750
2772
|
const manifestBranch = manifest?.branch;
|
|
2751
2773
|
if (manifestBranch) {
|
|
@@ -2967,6 +2989,7 @@ async function runManualWorktreeSession(config, issue, logFile, session, models,
|
|
|
2967
2989
|
}
|
|
2968
2990
|
ok(`PR created by provider: ${prUrl}`);
|
|
2969
2991
|
await appendPlatformAttribution(prUrl, result.providerUsed, config.platform);
|
|
2992
|
+
await applyPrReviewersAndAssignees(prUrl, config.pr, config.platform);
|
|
2970
2993
|
if (validationResults) {
|
|
2971
2994
|
await appendPlatformProofOfWork(prUrl, validationResults, config.platform);
|
|
2972
2995
|
}
|
|
@@ -3470,6 +3493,7 @@ async function runBranchSession(config, issue, logFile, session, models, source,
|
|
|
3470
3493
|
}
|
|
3471
3494
|
ok(`PR created by provider: ${prUrl}`);
|
|
3472
3495
|
await appendPlatformAttribution(prUrl, result.providerUsed, config.platform);
|
|
3496
|
+
await applyPrReviewersAndAssignees(prUrl, config.pr, config.platform);
|
|
3473
3497
|
if (validationResults) {
|
|
3474
3498
|
await appendPlatformProofOfWork(prUrl, validationResults, config.platform);
|
|
3475
3499
|
}
|
|
@@ -23,10 +23,15 @@ import {
|
|
|
23
23
|
getPlanPath
|
|
24
24
|
} from "./chunk-7OCDGYDM.js";
|
|
25
25
|
import {
|
|
26
|
+
addAssignees,
|
|
27
|
+
addReviewers,
|
|
26
28
|
appendPrAttribution,
|
|
27
29
|
appendPrBody,
|
|
30
|
+
getAuthenticatedUser,
|
|
31
|
+
parseBitbucketPrUrl,
|
|
32
|
+
parseGitLabMrUrl,
|
|
28
33
|
stripProviderAttribution
|
|
29
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-YMV4CBQE.js";
|
|
30
35
|
import {
|
|
31
36
|
formatError
|
|
32
37
|
} from "./chunk-7JT7DTSS.js";
|
|
@@ -3348,6 +3353,69 @@ async function appendPrBody2(prUrl, content) {
|
|
|
3348
3353
|
} catch {
|
|
3349
3354
|
}
|
|
3350
3355
|
}
|
|
3356
|
+
var accountIdCache = /* @__PURE__ */ new Map();
|
|
3357
|
+
async function resolveAccountIds(usernames) {
|
|
3358
|
+
const result = /* @__PURE__ */ new Map();
|
|
3359
|
+
const uncached = usernames.filter((u) => {
|
|
3360
|
+
const cached = accountIdCache.get(u);
|
|
3361
|
+
if (cached) {
|
|
3362
|
+
result.set(u, cached);
|
|
3363
|
+
return false;
|
|
3364
|
+
}
|
|
3365
|
+
return true;
|
|
3366
|
+
});
|
|
3367
|
+
if (uncached.length === 0) return result;
|
|
3368
|
+
const resolutions = await Promise.allSettled(
|
|
3369
|
+
uncached.map(async (username) => {
|
|
3370
|
+
const res = await fetch(`${API_URL3}/users/${encodeURIComponent(username)}`, {
|
|
3371
|
+
headers: { Authorization: getAuthHeader() },
|
|
3372
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS2)
|
|
3373
|
+
});
|
|
3374
|
+
if (!res.ok) return;
|
|
3375
|
+
const data = await res.json();
|
|
3376
|
+
if (data.account_id) {
|
|
3377
|
+
accountIdCache.set(username, data.account_id);
|
|
3378
|
+
result.set(username, data.account_id);
|
|
3379
|
+
}
|
|
3380
|
+
})
|
|
3381
|
+
);
|
|
3382
|
+
return result;
|
|
3383
|
+
}
|
|
3384
|
+
async function addPrReviewers(prUrl, reviewers) {
|
|
3385
|
+
if (!reviewers.length) return;
|
|
3386
|
+
const parsed = parseBitbucketPrUrl(prUrl);
|
|
3387
|
+
if (!parsed) return;
|
|
3388
|
+
const authHeader = getAuthHeader();
|
|
3389
|
+
const accountIds = await resolveAccountIds(reviewers);
|
|
3390
|
+
const getRes = await fetch(
|
|
3391
|
+
`${API_URL3}/repositories/${parsed.workspace}/${parsed.repoSlug}/pullrequests/${parsed.id}`,
|
|
3392
|
+
{
|
|
3393
|
+
headers: { Authorization: authHeader },
|
|
3394
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS2)
|
|
3395
|
+
}
|
|
3396
|
+
);
|
|
3397
|
+
if (!getRes.ok) throw new Error(`Bitbucket API error (${getRes.status})`);
|
|
3398
|
+
const prData = await getRes.json();
|
|
3399
|
+
const existingIds = new Set((prData.reviewers ?? []).map((r) => r.account_id));
|
|
3400
|
+
for (const [, accountId] of accountIds) {
|
|
3401
|
+
existingIds.add(accountId);
|
|
3402
|
+
}
|
|
3403
|
+
const authorId = prData.author?.account_id;
|
|
3404
|
+
if (authorId) existingIds.delete(authorId);
|
|
3405
|
+
const mergedReviewers = [...existingIds].map((account_id) => ({ account_id }));
|
|
3406
|
+
await fetch(
|
|
3407
|
+
`${API_URL3}/repositories/${parsed.workspace}/${parsed.repoSlug}/pullrequests/${parsed.id}`,
|
|
3408
|
+
{
|
|
3409
|
+
method: "PUT",
|
|
3410
|
+
headers: {
|
|
3411
|
+
Authorization: authHeader,
|
|
3412
|
+
"Content-Type": "application/json"
|
|
3413
|
+
},
|
|
3414
|
+
body: JSON.stringify({ title: prData.title, reviewers: mergedReviewers }),
|
|
3415
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS2)
|
|
3416
|
+
}
|
|
3417
|
+
);
|
|
3418
|
+
}
|
|
3351
3419
|
|
|
3352
3420
|
// src/git/gitlab.ts
|
|
3353
3421
|
import { execa as execa3 } from "execa";
|
|
@@ -3366,6 +3434,11 @@ function formatProviderName2(providerUsed) {
|
|
|
3366
3434
|
const providerKey = providerUsed.split("/")[0] ?? providerUsed;
|
|
3367
3435
|
return PROVIDER_DISPLAY_NAMES2[providerKey] ?? providerKey;
|
|
3368
3436
|
}
|
|
3437
|
+
function getToken() {
|
|
3438
|
+
const token = process.env.GITLAB_TOKEN;
|
|
3439
|
+
if (!token) throw new Error("GITLAB_TOKEN is not set");
|
|
3440
|
+
return token;
|
|
3441
|
+
}
|
|
3369
3442
|
function buildApiBase(host) {
|
|
3370
3443
|
return `https://${host}/api/v4`;
|
|
3371
3444
|
}
|
|
@@ -3432,6 +3505,105 @@ async function appendMrBody(mrUrl, content) {
|
|
|
3432
3505
|
} catch {
|
|
3433
3506
|
}
|
|
3434
3507
|
}
|
|
3508
|
+
var authenticatedUserCache = null;
|
|
3509
|
+
async function getGitLabAuthenticatedUser() {
|
|
3510
|
+
if (authenticatedUserCache) return authenticatedUserCache;
|
|
3511
|
+
const token = getToken();
|
|
3512
|
+
const res = await fetch("https://gitlab.com/api/v4/user", {
|
|
3513
|
+
headers: { "PRIVATE-TOKEN": token },
|
|
3514
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS3)
|
|
3515
|
+
});
|
|
3516
|
+
if (!res.ok) throw new Error(`GitLab API error (${res.status})`);
|
|
3517
|
+
const data = await res.json();
|
|
3518
|
+
authenticatedUserCache = data.username;
|
|
3519
|
+
return authenticatedUserCache;
|
|
3520
|
+
}
|
|
3521
|
+
var memberIdCache = /* @__PURE__ */ new Map();
|
|
3522
|
+
async function resolveUserIds(usernames, host, projectPath) {
|
|
3523
|
+
const result = /* @__PURE__ */ new Map();
|
|
3524
|
+
const uncached = usernames.filter((u) => {
|
|
3525
|
+
const cached = memberIdCache.get(u);
|
|
3526
|
+
if (cached !== void 0) {
|
|
3527
|
+
result.set(u, cached);
|
|
3528
|
+
return false;
|
|
3529
|
+
}
|
|
3530
|
+
return true;
|
|
3531
|
+
});
|
|
3532
|
+
if (uncached.length === 0) return result;
|
|
3533
|
+
const token = getToken();
|
|
3534
|
+
const apiBase = buildApiBase(host);
|
|
3535
|
+
const encodedPath = encodeURIComponent(projectPath);
|
|
3536
|
+
try {
|
|
3537
|
+
const membersRes = await fetch(`${apiBase}/projects/${encodedPath}/members/all?per_page=100`, {
|
|
3538
|
+
headers: { "PRIVATE-TOKEN": token },
|
|
3539
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS3)
|
|
3540
|
+
});
|
|
3541
|
+
if (membersRes.ok) {
|
|
3542
|
+
const members = await membersRes.json();
|
|
3543
|
+
for (const m of members) {
|
|
3544
|
+
memberIdCache.set(m.username, m.id);
|
|
3545
|
+
if (uncached.includes(m.username)) {
|
|
3546
|
+
result.set(m.username, m.id);
|
|
3547
|
+
}
|
|
3548
|
+
}
|
|
3549
|
+
}
|
|
3550
|
+
} catch {
|
|
3551
|
+
}
|
|
3552
|
+
const stillMissing = uncached.filter((u) => !result.has(u));
|
|
3553
|
+
const resolutions = await Promise.allSettled(
|
|
3554
|
+
stillMissing.map(async (username) => {
|
|
3555
|
+
const res = await fetch(`${apiBase}/users?username=${encodeURIComponent(username)}`, {
|
|
3556
|
+
headers: { "PRIVATE-TOKEN": token },
|
|
3557
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS3)
|
|
3558
|
+
});
|
|
3559
|
+
if (!res.ok) return;
|
|
3560
|
+
const users = await res.json();
|
|
3561
|
+
if (users[0]) {
|
|
3562
|
+
memberIdCache.set(users[0].username, users[0].id);
|
|
3563
|
+
result.set(username, users[0].id);
|
|
3564
|
+
}
|
|
3565
|
+
})
|
|
3566
|
+
);
|
|
3567
|
+
return result;
|
|
3568
|
+
}
|
|
3569
|
+
async function addMrReviewersAndAssignees(mrUrl, reviewerUsernames, assigneeUsernames) {
|
|
3570
|
+
if (!reviewerUsernames.length && !assigneeUsernames.length) return;
|
|
3571
|
+
const parsed = parseGitLabMrUrl(mrUrl);
|
|
3572
|
+
if (!parsed) return;
|
|
3573
|
+
const token = getToken();
|
|
3574
|
+
const apiBase = buildApiBase(parsed.host);
|
|
3575
|
+
const encodedPath = encodeURIComponent(parsed.projectPath);
|
|
3576
|
+
const allUsernames = [.../* @__PURE__ */ new Set([...reviewerUsernames, ...assigneeUsernames])];
|
|
3577
|
+
const idMap = await resolveUserIds(allUsernames, parsed.host, parsed.projectPath);
|
|
3578
|
+
const getRes = await fetch(`${apiBase}/projects/${encodedPath}/merge_requests/${parsed.iid}`, {
|
|
3579
|
+
headers: { "PRIVATE-TOKEN": token },
|
|
3580
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS3)
|
|
3581
|
+
});
|
|
3582
|
+
if (!getRes.ok) throw new Error(`GitLab API error (${getRes.status})`);
|
|
3583
|
+
const mrData = await getRes.json();
|
|
3584
|
+
const existingReviewerIds = new Set((mrData.reviewers ?? []).map((r) => r.id));
|
|
3585
|
+
const existingAssigneeIds = new Set((mrData.assignees ?? []).map((a) => a.id));
|
|
3586
|
+
for (const username of reviewerUsernames) {
|
|
3587
|
+
const id = idMap.get(username);
|
|
3588
|
+
if (id) existingReviewerIds.add(id);
|
|
3589
|
+
}
|
|
3590
|
+
for (const username of assigneeUsernames) {
|
|
3591
|
+
const id = idMap.get(username);
|
|
3592
|
+
if (id) existingAssigneeIds.add(id);
|
|
3593
|
+
}
|
|
3594
|
+
const body = {};
|
|
3595
|
+
if (reviewerUsernames.length) body.reviewer_ids = [...existingReviewerIds];
|
|
3596
|
+
if (assigneeUsernames.length) body.assignee_ids = [...existingAssigneeIds];
|
|
3597
|
+
await fetch(`${apiBase}/projects/${encodedPath}/merge_requests/${parsed.iid}`, {
|
|
3598
|
+
method: "PUT",
|
|
3599
|
+
headers: {
|
|
3600
|
+
"PRIVATE-TOKEN": token,
|
|
3601
|
+
"Content-Type": "application/json"
|
|
3602
|
+
},
|
|
3603
|
+
body: JSON.stringify(body),
|
|
3604
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS3)
|
|
3605
|
+
});
|
|
3606
|
+
}
|
|
3435
3607
|
|
|
3436
3608
|
// src/git/platform.ts
|
|
3437
3609
|
async function appendPlatformAttribution(prUrl, providerUsed, platform2) {
|
|
@@ -3508,6 +3680,52 @@ function buildPrCreateInstruction(platform2, targetBranch) {
|
|
|
3508
3680
|
\`gh pr create --title "<conventional-commit-title>" --body "<markdown-summary>"${base}\`
|
|
3509
3681
|
Capture the PR URL from the output.`;
|
|
3510
3682
|
}
|
|
3683
|
+
async function resolveAuthenticatedUser(platform2) {
|
|
3684
|
+
try {
|
|
3685
|
+
if (platform2 === "gitlab") {
|
|
3686
|
+
return await getGitLabAuthenticatedUser();
|
|
3687
|
+
}
|
|
3688
|
+
if (platform2 === "bitbucket") {
|
|
3689
|
+
return null;
|
|
3690
|
+
}
|
|
3691
|
+
return await getAuthenticatedUser(platform2);
|
|
3692
|
+
} catch {
|
|
3693
|
+
return null;
|
|
3694
|
+
}
|
|
3695
|
+
}
|
|
3696
|
+
async function applyPrReviewersAndAssignees(prUrl, prConfig, platform2) {
|
|
3697
|
+
if (!prConfig) return;
|
|
3698
|
+
const rawReviewers = prConfig.reviewers ?? [];
|
|
3699
|
+
const rawAssignees = prConfig.assignees ?? [];
|
|
3700
|
+
if (!rawReviewers.length && !rawAssignees.length) return;
|
|
3701
|
+
try {
|
|
3702
|
+
const hasSelf = rawReviewers.includes("self") || rawAssignees.includes("self");
|
|
3703
|
+
let selfUsername = null;
|
|
3704
|
+
if (hasSelf) {
|
|
3705
|
+
selfUsername = await resolveAuthenticatedUser(platform2);
|
|
3706
|
+
}
|
|
3707
|
+
const reviewers = rawReviewers.filter((r) => r !== "self").filter((r) => r !== selfUsername);
|
|
3708
|
+
const assignees = rawAssignees.map((a) => {
|
|
3709
|
+
if (a === "self") return selfUsername;
|
|
3710
|
+
return a;
|
|
3711
|
+
}).filter((a) => a !== null);
|
|
3712
|
+
if (selfUsername && rawReviewers.includes("self")) {
|
|
3713
|
+
warn("Filtered 'self' from reviewers \u2014 cannot request review from yourself");
|
|
3714
|
+
}
|
|
3715
|
+
if (platform2 === "gitlab") {
|
|
3716
|
+
await addMrReviewersAndAssignees(prUrl, reviewers, assignees);
|
|
3717
|
+
} else if (platform2 === "bitbucket") {
|
|
3718
|
+
if (reviewers.length) await addPrReviewers(prUrl, reviewers);
|
|
3719
|
+
} else {
|
|
3720
|
+
const tasks = [];
|
|
3721
|
+
if (reviewers.length) tasks.push(addReviewers(prUrl, reviewers));
|
|
3722
|
+
if (assignees.length) tasks.push(addAssignees(prUrl, assignees));
|
|
3723
|
+
await Promise.allSettled(tasks);
|
|
3724
|
+
}
|
|
3725
|
+
} catch (err) {
|
|
3726
|
+
warn(`Failed to add reviewers/assignees: ${formatError(err)}`);
|
|
3727
|
+
}
|
|
3728
|
+
}
|
|
3511
3729
|
|
|
3512
3730
|
// src/prompt.ts
|
|
3513
3731
|
function detectPackageManager(cwd) {
|
|
@@ -4109,6 +4327,7 @@ export {
|
|
|
4109
4327
|
appendPlatformAttribution,
|
|
4110
4328
|
appendPlatformProofOfWork,
|
|
4111
4329
|
appendPlatformSpecCompliance,
|
|
4330
|
+
applyPrReviewersAndAssignees,
|
|
4112
4331
|
detectPackageManager,
|
|
4113
4332
|
detectTestRunner,
|
|
4114
4333
|
buildImplementPrompt,
|
|
@@ -25,7 +25,32 @@ function stripProviderAttribution(body) {
|
|
|
25
25
|
return result.trimEnd();
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
// src/git/url-parser.ts
|
|
29
|
+
function parseGitHubPrUrl(prUrl) {
|
|
30
|
+
const match = prUrl.match(/github\.com\/([^/]+)\/([^/]+)\/pull\/(\d+)/);
|
|
31
|
+
if (!match) return null;
|
|
32
|
+
const num = Number.parseInt(match[3] ?? "0", 10);
|
|
33
|
+
if (num <= 0) return null;
|
|
34
|
+
return { owner: match[1] ?? "", repo: match[2] ?? "", number: num };
|
|
35
|
+
}
|
|
36
|
+
function parseGitLabMrUrl(mrUrl) {
|
|
37
|
+
const match = mrUrl.match(/https?:\/\/([^/]+)\/(.+?)\/-\/merge_requests\/(\d+)/);
|
|
38
|
+
if (!match) return null;
|
|
39
|
+
const iid = Number.parseInt(match[3] ?? "0", 10);
|
|
40
|
+
if (iid <= 0) return null;
|
|
41
|
+
return { host: match[1] ?? "", projectPath: match[2] ?? "", iid };
|
|
42
|
+
}
|
|
43
|
+
function parseBitbucketPrUrl(prUrl) {
|
|
44
|
+
const match = prUrl.match(/bitbucket\.org\/([^/]+)\/([^/]+)\/pull-requests\/(\d+)/);
|
|
45
|
+
if (!match) return null;
|
|
46
|
+
const id = Number.parseInt(match[3] ?? "0", 10);
|
|
47
|
+
if (id <= 0) return null;
|
|
48
|
+
return { workspace: match[1] ?? "", repoSlug: match[2] ?? "", id };
|
|
49
|
+
}
|
|
50
|
+
|
|
28
51
|
// src/git/github.ts
|
|
52
|
+
var API_URL = "https://api.github.com";
|
|
53
|
+
var REQUEST_TIMEOUT_MS = 3e4;
|
|
29
54
|
async function isGhCliAvailable() {
|
|
30
55
|
try {
|
|
31
56
|
await execa("gh", ["auth", "status"]);
|
|
@@ -34,6 +59,11 @@ async function isGhCliAvailable() {
|
|
|
34
59
|
return false;
|
|
35
60
|
}
|
|
36
61
|
}
|
|
62
|
+
function getToken() {
|
|
63
|
+
const token = process.env.GITHUB_TOKEN;
|
|
64
|
+
if (!token) throw new Error("GITHUB_TOKEN is not set");
|
|
65
|
+
return token;
|
|
66
|
+
}
|
|
37
67
|
var PROVIDER_DISPLAY_NAMES = {
|
|
38
68
|
claude: "Claude Code",
|
|
39
69
|
gemini: "Gemini CLI",
|
|
@@ -107,10 +137,73 @@ async function appendPrBody(prUrl, content) {
|
|
|
107
137
|
} catch {
|
|
108
138
|
}
|
|
109
139
|
}
|
|
140
|
+
var authenticatedUserCache = null;
|
|
141
|
+
async function getAuthenticatedUser(method = "cli") {
|
|
142
|
+
if (authenticatedUserCache) return authenticatedUserCache;
|
|
143
|
+
if (method === "cli" || method === "token") {
|
|
144
|
+
if (method === "cli") {
|
|
145
|
+
const { stdout } = await execa("gh", ["api", "/user", "--jq", ".login"]);
|
|
146
|
+
authenticatedUserCache = stdout.trim();
|
|
147
|
+
} else {
|
|
148
|
+
const res = await fetch(`${API_URL}/user`, {
|
|
149
|
+
headers: { Authorization: `Bearer ${getToken()}`, Accept: "application/vnd.github+json" },
|
|
150
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
151
|
+
});
|
|
152
|
+
if (!res.ok) throw new Error(`GitHub API error (${res.status})`);
|
|
153
|
+
const data = await res.json();
|
|
154
|
+
authenticatedUserCache = data.login;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (!authenticatedUserCache) throw new Error("Could not resolve authenticated GitHub user");
|
|
158
|
+
return authenticatedUserCache;
|
|
159
|
+
}
|
|
160
|
+
async function addReviewers(prUrl, reviewers) {
|
|
161
|
+
if (!reviewers.length) return;
|
|
162
|
+
const parsed = parseGitHubPrUrl(prUrl);
|
|
163
|
+
if (!parsed) return;
|
|
164
|
+
await execa(
|
|
165
|
+
"gh",
|
|
166
|
+
[
|
|
167
|
+
"api",
|
|
168
|
+
"--method",
|
|
169
|
+
"POST",
|
|
170
|
+
`/repos/${parsed.owner}/${parsed.repo}/pulls/${parsed.number}/requested_reviewers`,
|
|
171
|
+
"--input",
|
|
172
|
+
"-"
|
|
173
|
+
],
|
|
174
|
+
{
|
|
175
|
+
input: JSON.stringify({ reviewers })
|
|
176
|
+
}
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
async function addAssignees(prUrl, assignees) {
|
|
180
|
+
if (!assignees.length) return;
|
|
181
|
+
const parsed = parseGitHubPrUrl(prUrl);
|
|
182
|
+
if (!parsed) return;
|
|
183
|
+
await execa(
|
|
184
|
+
"gh",
|
|
185
|
+
[
|
|
186
|
+
"api",
|
|
187
|
+
"--method",
|
|
188
|
+
"POST",
|
|
189
|
+
`/repos/${parsed.owner}/${parsed.repo}/issues/${parsed.number}/assignees`,
|
|
190
|
+
"--input",
|
|
191
|
+
"-"
|
|
192
|
+
],
|
|
193
|
+
{
|
|
194
|
+
input: JSON.stringify({ assignees })
|
|
195
|
+
}
|
|
196
|
+
);
|
|
197
|
+
}
|
|
110
198
|
|
|
111
199
|
export {
|
|
112
200
|
stripProviderAttribution,
|
|
201
|
+
parseGitLabMrUrl,
|
|
202
|
+
parseBitbucketPrUrl,
|
|
113
203
|
isGhCliAvailable,
|
|
114
204
|
appendPrAttribution,
|
|
115
|
-
appendPrBody
|
|
205
|
+
appendPrBody,
|
|
206
|
+
getAuthenticatedUser,
|
|
207
|
+
addReviewers,
|
|
208
|
+
addAssignees
|
|
116
209
|
};
|
|
@@ -12,8 +12,8 @@ import {
|
|
|
12
12
|
getVersion,
|
|
13
13
|
isCursorFreePlan,
|
|
14
14
|
verifyPlatformCredential
|
|
15
|
-
} from "./chunk-
|
|
16
|
-
import "./chunk-
|
|
15
|
+
} from "./chunk-R6D5VH65.js";
|
|
16
|
+
import "./chunk-YMV4CBQE.js";
|
|
17
17
|
import "./chunk-7JT7DTSS.js";
|
|
18
18
|
export {
|
|
19
19
|
detectDefaultBranch,
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
parseStructuredOutput,
|
|
8
8
|
runPlanWizard,
|
|
9
9
|
savePlan
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-K2ILRYXS.js";
|
|
11
11
|
import {
|
|
12
12
|
detectDefaultBranch,
|
|
13
13
|
detectGitRepos,
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
getMissingEnvVars,
|
|
19
19
|
getVersion,
|
|
20
20
|
isCursorFreePlan
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-R6D5VH65.js";
|
|
22
22
|
import {
|
|
23
23
|
getCachedUpdateInfo
|
|
24
24
|
} from "./chunk-7CIXBENY.js";
|
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
runLoop,
|
|
37
37
|
saveConfig,
|
|
38
38
|
validateConfig
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-AAWXKEV7.js";
|
|
40
40
|
import {
|
|
41
41
|
buildContextMdBlock,
|
|
42
42
|
createProvider,
|
|
@@ -48,7 +48,7 @@ import {
|
|
|
48
48
|
readContext,
|
|
49
49
|
resolveModels,
|
|
50
50
|
runWithFallback
|
|
51
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-NHC3JG2C.js";
|
|
52
52
|
import {
|
|
53
53
|
banner,
|
|
54
54
|
error,
|
|
@@ -67,7 +67,7 @@ import {
|
|
|
67
67
|
import "./chunk-72CYGBT4.js";
|
|
68
68
|
import {
|
|
69
69
|
isGhCliAvailable
|
|
70
|
-
} from "./chunk-
|
|
70
|
+
} from "./chunk-YMV4CBQE.js";
|
|
71
71
|
import {
|
|
72
72
|
formatError
|
|
73
73
|
} from "./chunk-7JT7DTSS.js";
|
|
@@ -1001,6 +1001,23 @@ function runAdvancedChecks(config2) {
|
|
|
1001
1001
|
suggestion: existsSync(contextPath) ? void 0 : 'Run "lisa context refresh" to generate .lisa/context.md for better planning.',
|
|
1002
1002
|
category: "advanced"
|
|
1003
1003
|
});
|
|
1004
|
+
if (config2.pr) {
|
|
1005
|
+
if (config2.platform === "bitbucket" && config2.pr.assignees?.length) {
|
|
1006
|
+
results.push({
|
|
1007
|
+
passed: false,
|
|
1008
|
+
label: "PR assignees compatible with platform",
|
|
1009
|
+
suggestion: "Bitbucket does not support PR assignees. Remove pr.assignees or switch platform.",
|
|
1010
|
+
category: "advanced"
|
|
1011
|
+
});
|
|
1012
|
+
}
|
|
1013
|
+
if (config2.pr.reviewers?.length || config2.pr.assignees?.length) {
|
|
1014
|
+
results.push({
|
|
1015
|
+
passed: true,
|
|
1016
|
+
label: `PR config: ${config2.pr.reviewers?.length ?? 0} reviewer(s), ${config2.pr.assignees?.length ?? 0} assignee(s)`,
|
|
1017
|
+
category: "advanced"
|
|
1018
|
+
});
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1004
1021
|
return results;
|
|
1005
1022
|
}
|
|
1006
1023
|
var doctor = defineCommand3({
|
|
@@ -1527,7 +1544,7 @@ async function reviewAndCreate(plan2, planPath, opts) {
|
|
|
1527
1544
|
log("Run `lisa run` when ready.");
|
|
1528
1545
|
return;
|
|
1529
1546
|
}
|
|
1530
|
-
const { runLoop: runLoop2 } = await import("./loop-
|
|
1547
|
+
const { runLoop: runLoop2 } = await import("./loop-PXUNTCQS.js");
|
|
1531
1548
|
await runLoop2(config2, {
|
|
1532
1549
|
once: false,
|
|
1533
1550
|
watch: false,
|
|
@@ -1891,7 +1908,7 @@ async function executeRun(args) {
|
|
|
1891
1908
|
if (isTTY) {
|
|
1892
1909
|
const { render } = await import("ink");
|
|
1893
1910
|
const { createElement } = await import("react");
|
|
1894
|
-
const { KanbanApp } = await import("./kanban-
|
|
1911
|
+
const { KanbanApp } = await import("./kanban-F27DQLKJ.js");
|
|
1895
1912
|
const demoConfig = {
|
|
1896
1913
|
provider: "claude",
|
|
1897
1914
|
source: "linear",
|
|
@@ -1991,7 +2008,7 @@ Add them to your ${shell} and run: source ${shell}`));
|
|
|
1991
2008
|
const initialCards = persistence.load();
|
|
1992
2009
|
persistedCards = initialCards;
|
|
1993
2010
|
persistence.start();
|
|
1994
|
-
const { registerPlanBridge } = await import("./tui-bridge-
|
|
2011
|
+
const { registerPlanBridge } = await import("./tui-bridge-WKKIHWJT.js");
|
|
1995
2012
|
const cleanupPlan = registerPlanBridge(merged);
|
|
1996
2013
|
onBeforeExit = () => {
|
|
1997
2014
|
persistence.stop();
|
|
@@ -1999,7 +2016,7 @@ Add them to your ${shell} and run: source ${shell}`));
|
|
|
1999
2016
|
};
|
|
2000
2017
|
const { render } = await import("ink");
|
|
2001
2018
|
const { createElement } = await import("react");
|
|
2002
|
-
const { KanbanApp } = await import("./kanban-
|
|
2019
|
+
const { KanbanApp } = await import("./kanban-F27DQLKJ.js");
|
|
2003
2020
|
render(createElement(KanbanApp, { config: merged, initialCards }), { exitOnCtrlC: false });
|
|
2004
2021
|
}
|
|
2005
2022
|
await runLoop(merged, {
|
|
@@ -2047,6 +2064,7 @@ var status = defineCommand9({
|
|
|
2047
2064
|
label: formatLabels(config2.source_config),
|
|
2048
2065
|
scope: config2.source_config.scope,
|
|
2049
2066
|
platform: config2.platform,
|
|
2067
|
+
pr: config2.pr ?? null,
|
|
2050
2068
|
logsDir,
|
|
2051
2069
|
sessionCount
|
|
2052
2070
|
},
|
|
@@ -2070,6 +2088,17 @@ var status = defineCommand9({
|
|
|
2070
2088
|
console.log(` Pick from: ${pc7.bold(config2.source_config.pick_from)}`);
|
|
2071
2089
|
console.log(` In progress: ${pc7.bold(config2.source_config.in_progress)}`);
|
|
2072
2090
|
console.log(` Done: ${pc7.bold(config2.source_config.done)}`);
|
|
2091
|
+
if (config2.pr) {
|
|
2092
|
+
const reviewers = config2.pr.reviewers?.join(", ") ?? pc7.dim("none");
|
|
2093
|
+
const assignees = config2.pr.assignees?.join(", ") ?? pc7.dim("none");
|
|
2094
|
+
console.log(` Reviewers: ${pc7.bold(reviewers)}`);
|
|
2095
|
+
console.log(` Assignees: ${pc7.bold(assignees)}`);
|
|
2096
|
+
if (config2.platform === "bitbucket" && config2.pr.assignees?.length) {
|
|
2097
|
+
console.log(
|
|
2098
|
+
` ${pc7.yellow("!")} Bitbucket does not support assignees \u2014 only reviewers will be added`
|
|
2099
|
+
);
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2073
2102
|
console.log(` Logs: ${pc7.dim(logsDir)}`);
|
|
2074
2103
|
if (sessionCount > 0) {
|
|
2075
2104
|
console.log(`
|
|
@@ -2111,7 +2140,7 @@ process.on("unhandledRejection", (err) => {
|
|
|
2111
2140
|
}
|
|
2112
2141
|
process.exit(1);
|
|
2113
2142
|
});
|
|
2114
|
-
import("./detection-
|
|
2143
|
+
import("./detection-H5QJR5XI.js").then(
|
|
2115
2144
|
({ getVersion: getVersion2 }) => import("./version-D2YFKS7Q.js").then(({ checkForUpdate }) => checkForUpdate(getVersion2()))
|
|
2116
2145
|
);
|
|
2117
2146
|
runCli();
|
|
@@ -130,9 +130,12 @@ function Card({
|
|
|
130
130
|
card.column === "in_progress" ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", marginTop: 0, children: [
|
|
131
131
|
isPausedInProgress ? /* @__PURE__ */ jsx(Text, { color: "gray", children: "\u23F8" }) : /* @__PURE__ */ jsx(Text, { color: "yellow", children: /* @__PURE__ */ jsx(Spinner, { type: "dots" }) }),
|
|
132
132
|
/* @__PURE__ */ jsx(Text, { color: isPausedInProgress ? "gray" : "yellow", dimColor: isPausedInProgress, children: elapsedMs !== null ? ` ${formatElapsed(elapsedMs)}` : "" })
|
|
133
|
-
] }) : card.column === "done" && card.startedAt !== void 0 && card.finishedAt !== void 0 ? /* @__PURE__ */ jsxs(
|
|
134
|
-
"
|
|
135
|
-
|
|
133
|
+
] }) : card.column === "done" && card.startedAt !== void 0 && card.finishedAt !== void 0 ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", justifyContent: "space-between", children: [
|
|
134
|
+
/* @__PURE__ */ jsxs(Text, { color: card.merged ? "magenta" : "green", children: [
|
|
135
|
+
"\u2714 ",
|
|
136
|
+
formatElapsed(card.finishedAt - card.startedAt)
|
|
137
|
+
] }),
|
|
138
|
+
card.prUrls.length > 0 && /* @__PURE__ */ jsx(Text, { color: card.merged ? "magenta" : "yellow", dimColor: true, children: card.merged ? "PR\u2714" : "PR" })
|
|
136
139
|
] }) : card.killed ? /* @__PURE__ */ jsx(Text, { color: "red", children: "KILLED" }) : card.skipped ? /* @__PURE__ */ jsx(Text, { color: "gray", children: "SKIPPED" }) : card.hasError && !card.killed && !card.skipped ? /* @__PURE__ */ jsx(Text, { color: "red", children: "FAILED" }) : (
|
|
137
140
|
// Empty row for backlog and done-without-timing — maintains CARD_HEIGHT
|
|
138
141
|
/* @__PURE__ */ jsx(Text, { children: " ".repeat(cardWidth) })
|
|
@@ -390,7 +393,7 @@ function logLineColor(line) {
|
|
|
390
393
|
}
|
|
391
394
|
|
|
392
395
|
// src/ui/detail.tsx
|
|
393
|
-
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
396
|
+
import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
394
397
|
function openUrl(url) {
|
|
395
398
|
const platform = process.platform;
|
|
396
399
|
let command;
|
|
@@ -443,7 +446,7 @@ function statusLabel(column, hasError, killed, skipped, merged) {
|
|
|
443
446
|
if (column === "done") return { text: "DONE", color: "green" };
|
|
444
447
|
return { text: "QUEUED", color: "white" };
|
|
445
448
|
}
|
|
446
|
-
function IssueDetail({ card, onBack }) {
|
|
449
|
+
function IssueDetail({ card, onBack, reviewers, assignees }) {
|
|
447
450
|
const [now, setNow] = useState3(Date.now());
|
|
448
451
|
const [logScrollOffset, setLogScrollOffset] = useState3(0);
|
|
449
452
|
const [userScrolled, setUserScrolled] = useState3(false);
|
|
@@ -488,7 +491,9 @@ function IssueDetail({ card, onBack }) {
|
|
|
488
491
|
const maxLineWidth = Math.max(1, terminalCols - SIDEBAR_TOTAL_WIDTH4 - 4);
|
|
489
492
|
const prCount = card.prUrls.length > 0 ? card.prUrls.length : 0;
|
|
490
493
|
const logFileRow = card.logFile ? 1 : 0;
|
|
491
|
-
const
|
|
494
|
+
const hasPrMeta = card.column === "done" && (reviewers?.length || assignees?.length);
|
|
495
|
+
const prMetaRow = hasPrMeta ? 1 : 0;
|
|
496
|
+
const headerOverhead = 6 + prCount + logFileRow + prMetaRow;
|
|
492
497
|
const bodyRows = Math.max(1, terminalRows - headerOverhead);
|
|
493
498
|
const lines = useMemo(() => processOutputLines(card.outputLog), [card.outputLog]);
|
|
494
499
|
const startLine = Math.max(0, lines.length - bodyRows - logScrollOffset);
|
|
@@ -548,6 +553,17 @@ function IssueDetail({ card, onBack }) {
|
|
|
548
553
|
/* @__PURE__ */ jsx4(Text4, { color: "yellow", dimColor: true, children: card.prUrls.length === 1 ? "PR: " : `PR ${i + 1}: ` }),
|
|
549
554
|
/* @__PURE__ */ jsx4(Text4, { color: "yellow", wrap: "truncate", children: hyperlink(url, truncateLine(url, maxLineWidth - 5)) })
|
|
550
555
|
] }, url)),
|
|
556
|
+
hasPrMeta && /* @__PURE__ */ jsxs4(Box4, { marginTop: 0, flexDirection: "row", children: [
|
|
557
|
+
reviewers?.length ? /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
558
|
+
/* @__PURE__ */ jsx4(Text4, { color: "cyan", dimColor: true, children: "REVIEWERS: " }),
|
|
559
|
+
/* @__PURE__ */ jsx4(Text4, { color: "cyan", children: reviewers.join(", ") })
|
|
560
|
+
] }) : null,
|
|
561
|
+
reviewers?.length && assignees?.length ? /* @__PURE__ */ jsx4(Text4, { color: "gray", dimColor: true, children: " \u2502 " }) : null,
|
|
562
|
+
assignees?.length ? /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
563
|
+
/* @__PURE__ */ jsx4(Text4, { color: "green", dimColor: true, children: "ASSIGNEES: " }),
|
|
564
|
+
/* @__PURE__ */ jsx4(Text4, { color: "green", children: assignees.map((a) => a === "self" ? "you" : a).join(", ") })
|
|
565
|
+
] }) : null
|
|
566
|
+
] }),
|
|
551
567
|
card.logFile && /* @__PURE__ */ jsx4(Box4, { marginTop: 0, children: /* @__PURE__ */ jsx4(Text4, { color: "gray", dimColor: true, wrap: "truncate", children: `LOG: ${truncateLine(card.logFile, maxLineWidth - 5)}` }) }),
|
|
552
568
|
/* @__PURE__ */ jsx4(Box4, { children: /* @__PURE__ */ jsx4(Text4, { color: "yellow", dimColor: true, children: separator }) }),
|
|
553
569
|
/* @__PURE__ */ jsxs4(Box4, { flexDirection: "row", justifyContent: "space-between", children: [
|
|
@@ -875,7 +891,7 @@ function PlanReview({ goal, issues, selectedIndex }) {
|
|
|
875
891
|
import { existsSync } from "fs";
|
|
876
892
|
import { basename, join } from "path";
|
|
877
893
|
import { Box as Box8, Text as Text8 } from "ink";
|
|
878
|
-
import { Fragment as
|
|
894
|
+
import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
879
895
|
function Sidebar({
|
|
880
896
|
provider,
|
|
881
897
|
model,
|
|
@@ -890,7 +906,9 @@ function Sidebar({
|
|
|
890
906
|
mergeConfirm = null,
|
|
891
907
|
merging = null,
|
|
892
908
|
updateInfo = null,
|
|
893
|
-
workComplete = null
|
|
909
|
+
workComplete = null,
|
|
910
|
+
reviewers,
|
|
911
|
+
assignees
|
|
894
912
|
}) {
|
|
895
913
|
const dir = basename(cwd).toUpperCase();
|
|
896
914
|
const cwdLabel = existsSync(join(cwd, ".git")) ? "REPOSITORY" : "WORKSPACE";
|
|
@@ -916,10 +934,10 @@ function Sidebar({
|
|
|
916
934
|
] }),
|
|
917
935
|
/* @__PURE__ */ jsx8(Text8, { color: "yellow", children: "\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D" })
|
|
918
936
|
] }),
|
|
919
|
-
/* @__PURE__ */ jsx8(Box8, { marginBottom: 1, children: activeView === "idle" || activeView === "empty" ? /* @__PURE__ */ jsxs8(
|
|
937
|
+
/* @__PURE__ */ jsx8(Box8, { marginBottom: 1, children: activeView === "idle" || activeView === "empty" ? /* @__PURE__ */ jsxs8(Fragment3, { children: [
|
|
920
938
|
/* @__PURE__ */ jsx8(Text8, { color: "gray", children: "\u25C7 " }),
|
|
921
939
|
/* @__PURE__ */ jsx8(Text8, { color: "gray", bold: true, children: "IDLE" })
|
|
922
|
-
] }) : /* @__PURE__ */ jsxs8(
|
|
940
|
+
] }) : /* @__PURE__ */ jsxs8(Fragment3, { children: [
|
|
923
941
|
/* @__PURE__ */ jsx8(Text8, { color: paused ? "yellow" : "green", children: paused ? "\u23F8 " : "\u25B6 " }),
|
|
924
942
|
/* @__PURE__ */ jsx8(Text8, { color: paused ? "yellow" : "green", bold: true, children: paused ? "PAUSED" : "RUNNING" })
|
|
925
943
|
] }) }),
|
|
@@ -989,7 +1007,24 @@ function Sidebar({
|
|
|
989
1007
|
canMerge && !merging && !mergeConfirm && /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "[m] merge" }),
|
|
990
1008
|
merging && /* @__PURE__ */ jsx8(Text8, { color: "yellow", children: "\u23F3 merging..." }),
|
|
991
1009
|
mergeConfirm && /* @__PURE__ */ jsx8(Text8, { color: "yellow", children: "\u26A0 CI not passed\n merge? [y/n]" }),
|
|
992
|
-
/* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "[Esc] back" })
|
|
1010
|
+
/* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "[Esc] back" }),
|
|
1011
|
+
hasPrUrl && (reviewers?.length || assignees?.length) ? /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
|
|
1012
|
+
/* @__PURE__ */ jsx8(Text8, { color: "yellow", children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
|
|
1013
|
+
reviewers?.length ? /* @__PURE__ */ jsx8(
|
|
1014
|
+
Text8,
|
|
1015
|
+
{
|
|
1016
|
+
dimColor: true,
|
|
1017
|
+
children: `\u{1F440} ${reviewers.length} reviewer${reviewers.length > 1 ? "s" : ""}`
|
|
1018
|
+
}
|
|
1019
|
+
) : null,
|
|
1020
|
+
assignees?.length ? /* @__PURE__ */ jsx8(
|
|
1021
|
+
Text8,
|
|
1022
|
+
{
|
|
1023
|
+
dimColor: true,
|
|
1024
|
+
children: `\u{1F464} ${assignees.map((a) => a === "self" ? "you" : a).join(", ")}`
|
|
1025
|
+
}
|
|
1026
|
+
) : null
|
|
1027
|
+
] }) : null
|
|
993
1028
|
] }),
|
|
994
1029
|
activeView === "watching" && /* @__PURE__ */ jsx8(Box8, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "[q] quit" }) }),
|
|
995
1030
|
activeView === "watch-prompt" && /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
|
|
@@ -1402,7 +1437,9 @@ Merge failed: ${result.error}
|
|
|
1402
1437
|
mergeConfirm,
|
|
1403
1438
|
merging,
|
|
1404
1439
|
updateInfo,
|
|
1405
|
-
workComplete
|
|
1440
|
+
workComplete,
|
|
1441
|
+
reviewers: config.pr?.reviewers,
|
|
1442
|
+
assignees: config.pr?.assignees
|
|
1406
1443
|
}
|
|
1407
1444
|
),
|
|
1408
1445
|
activeView === "plan-chat" ? /* @__PURE__ */ jsx9(
|
|
@@ -1473,7 +1510,9 @@ Merge failed: ${result.error}
|
|
|
1473
1510
|
onBack: () => {
|
|
1474
1511
|
setActiveView("board");
|
|
1475
1512
|
setSelectedCardId(null);
|
|
1476
|
-
}
|
|
1513
|
+
},
|
|
1514
|
+
reviewers: config.pr?.reviewers,
|
|
1515
|
+
assignees: config.pr?.assignees
|
|
1477
1516
|
}
|
|
1478
1517
|
)
|
|
1479
1518
|
] });
|
|
@@ -3,15 +3,15 @@ import {
|
|
|
3
3
|
checkoutBaseBranches,
|
|
4
4
|
runDemoLoop,
|
|
5
5
|
runLoop
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-AAWXKEV7.js";
|
|
7
7
|
import {
|
|
8
8
|
WATCH_POLL_INTERVAL_MS
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-NHC3JG2C.js";
|
|
10
10
|
import "./chunk-66TB6NMR.js";
|
|
11
11
|
import "./chunk-3EOEDL3T.js";
|
|
12
12
|
import "./chunk-7OCDGYDM.js";
|
|
13
13
|
import "./chunk-72CYGBT4.js";
|
|
14
|
-
import "./chunk-
|
|
14
|
+
import "./chunk-YMV4CBQE.js";
|
|
15
15
|
import "./chunk-7JT7DTSS.js";
|
|
16
16
|
import "./chunk-DGL33SDZ.js";
|
|
17
17
|
export {
|
|
@@ -6,12 +6,12 @@ import {
|
|
|
6
6
|
markdownToIssue,
|
|
7
7
|
parseStructuredOutput,
|
|
8
8
|
savePlan
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-K2ILRYXS.js";
|
|
10
10
|
import {
|
|
11
11
|
createSource,
|
|
12
12
|
resolveModels,
|
|
13
13
|
runWithFallback
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-NHC3JG2C.js";
|
|
15
15
|
import {
|
|
16
16
|
error,
|
|
17
17
|
kanbanEmitter,
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
import "./chunk-3EOEDL3T.js";
|
|
23
23
|
import "./chunk-7OCDGYDM.js";
|
|
24
24
|
import "./chunk-72CYGBT4.js";
|
|
25
|
-
import "./chunk-
|
|
25
|
+
import "./chunk-YMV4CBQE.js";
|
|
26
26
|
import "./chunk-7JT7DTSS.js";
|
|
27
27
|
|
|
28
28
|
// src/plan/tui-bridge.ts
|