@tarcisiopgs/lisa 0.9.3 → 0.9.5
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/dist/index.js +260 -29
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
4
|
import { execSync as execSync4 } from "child_process";
|
|
5
|
-
import { existsSync as
|
|
5
|
+
import { existsSync as existsSync7, readdirSync, readFileSync as readFileSync6 } from "fs";
|
|
6
6
|
import { join as join8, resolve as resolvePath } from "path";
|
|
7
7
|
import * as clack from "@clack/prompts";
|
|
8
8
|
import { defineCommand, runMain } from "citty";
|
|
@@ -331,7 +331,7 @@ function banner() {
|
|
|
331
331
|
}
|
|
332
332
|
|
|
333
333
|
// src/loop.ts
|
|
334
|
-
import { appendFileSync as appendFileSync6, readFileSync as readFileSync5, unlinkSync as unlinkSync4 } from "fs";
|
|
334
|
+
import { appendFileSync as appendFileSync6, existsSync as existsSync6, readFileSync as readFileSync5, unlinkSync as unlinkSync4 } from "fs";
|
|
335
335
|
import { join as join7, resolve as resolve5 } from "path";
|
|
336
336
|
import { execa as execa3 } from "execa";
|
|
337
337
|
|
|
@@ -554,6 +554,96 @@ Do NOT update README.md for:
|
|
|
554
554
|
If an update is needed, keep the existing README style and structure. Include the README change in the same commit as the implementation.
|
|
555
555
|
`;
|
|
556
556
|
}
|
|
557
|
+
function buildWorktreeMultiRepoPrompt(issue, config2) {
|
|
558
|
+
const workspace = resolve3(config2.workspace);
|
|
559
|
+
const repoBlock = config2.repos.map((r) => {
|
|
560
|
+
const absPath = resolve3(workspace, r.path);
|
|
561
|
+
return [
|
|
562
|
+
`- **${r.name}**: \`${absPath}\``,
|
|
563
|
+
` - Base branch: \`${r.base_branch}\``,
|
|
564
|
+
` - Worktrees dir: \`${join(absPath, ".worktrees")}\``
|
|
565
|
+
].join("\n");
|
|
566
|
+
}).join("\n\n");
|
|
567
|
+
const readmeBlock = buildReadmeInstructions();
|
|
568
|
+
const manifestPath = join(workspace, ".lisa-manifest.json");
|
|
569
|
+
return `You are an autonomous implementation agent working in a multi-repository workspace.
|
|
570
|
+
Your job is to determine the correct repository, create an English-named branch, implement the issue, commit, and write a manifest file.
|
|
571
|
+
|
|
572
|
+
You are in the workspace: \`${workspace}\`
|
|
573
|
+
|
|
574
|
+
## Issue
|
|
575
|
+
|
|
576
|
+
- **ID:** ${issue.id}
|
|
577
|
+
- **Title:** ${issue.title}
|
|
578
|
+
- **URL:** ${issue.url}
|
|
579
|
+
|
|
580
|
+
### Description
|
|
581
|
+
|
|
582
|
+
${issue.description}
|
|
583
|
+
|
|
584
|
+
## Available Repositories
|
|
585
|
+
|
|
586
|
+
${repoBlock}
|
|
587
|
+
|
|
588
|
+
## Instructions
|
|
589
|
+
|
|
590
|
+
1. **Identify the correct repository**: Read the issue title and description carefully.
|
|
591
|
+
Determine which single repository above is the right target. Consider:
|
|
592
|
+
- File paths or module names mentioned in the description
|
|
593
|
+
- Technologies and frameworks referenced
|
|
594
|
+
- The nature of the change (e.g., API endpoint \u2192 api repo, UI component \u2192 frontend repo)
|
|
595
|
+
|
|
596
|
+
2. **Choose an English branch name**: Create a slug in English following:
|
|
597
|
+
\`feat/${issue.id.toLowerCase()}-short-english-description\`
|
|
598
|
+
The description part MUST be in English regardless of the issue title language.
|
|
599
|
+
Example: for "${issue.id} Implementar rate limiting na API" \u2192 \`feat/${issue.id.toLowerCase()}-add-rate-limiting-to-api\`
|
|
600
|
+
|
|
601
|
+
3. **Set up the worktree**: In the chosen repo, run:
|
|
602
|
+
\`\`\`
|
|
603
|
+
git fetch origin <base_branch>
|
|
604
|
+
git worktree add -b <your-english-branch> <repoPath>/.worktrees/<your-english-branch> origin/<base_branch>
|
|
605
|
+
cd <repoPath>/.worktrees/<your-english-branch>
|
|
606
|
+
\`\`\`
|
|
607
|
+
|
|
608
|
+
4. **Implement**: Work inside the worktree. Follow the issue description exactly:
|
|
609
|
+
- Read all relevant files listed in the description first (if present)
|
|
610
|
+
- Follow the implementation instructions exactly
|
|
611
|
+
- Verify each acceptance criteria (if present)
|
|
612
|
+
- Respect any stack or technical constraints (if present)
|
|
613
|
+
${readmeBlock}
|
|
614
|
+
5. **Validate**: Run the project's linter/typecheck/tests if available:
|
|
615
|
+
- Check \`package.json\` for lint, typecheck, check, or test scripts.
|
|
616
|
+
- Run whichever validation scripts exist (e.g., \`npm run lint\`, \`npm run typecheck\`, \`npm run test\`).
|
|
617
|
+
- Fix any errors before proceeding.
|
|
618
|
+
|
|
619
|
+
6. **Commit (do NOT push)**: Make atomic commits with conventional commit messages.
|
|
620
|
+
Do NOT run \`git push\` \u2014 the caller handles pushing.
|
|
621
|
+
**IMPORTANT \u2014 Language rules:**
|
|
622
|
+
- All commit messages MUST be in English.
|
|
623
|
+
- Use conventional commits format: \`feat: ...\`, \`fix: ...\`, \`refactor: ...\`, \`chore: ...\`
|
|
624
|
+
|
|
625
|
+
7. **Write the manifest**: After committing, create \`${manifestPath}\` with JSON:
|
|
626
|
+
\`\`\`json
|
|
627
|
+
{
|
|
628
|
+
"repoPath": "<absolute path to the chosen repo>",
|
|
629
|
+
"branch": "<your English branch name>",
|
|
630
|
+
"prTitle": "<PR title in English, conventional commit format>"
|
|
631
|
+
}
|
|
632
|
+
\`\`\`
|
|
633
|
+
Do NOT commit this file.
|
|
634
|
+
|
|
635
|
+
## Rules
|
|
636
|
+
|
|
637
|
+
- **ALL git commits, branch names, PR titles, and PR descriptions MUST be in English.**
|
|
638
|
+
- The issue description may be in any language \u2014 read it for context but write all code artifacts in English.
|
|
639
|
+
- Do NOT push \u2014 the caller handles that.
|
|
640
|
+
- Do NOT create pull requests \u2014 the caller handles that.
|
|
641
|
+
- Do NOT update the issue tracker \u2014 the caller handles that.
|
|
642
|
+
- Do NOT install new dependencies unless the issue explicitly requires it.
|
|
643
|
+
- If you get stuck or the issue is unclear, STOP and explain why.
|
|
644
|
+
- One issue only. Do not pick up additional issues.
|
|
645
|
+
- If the repo has a CLAUDE.md, read it first and follow its conventions.`;
|
|
646
|
+
}
|
|
557
647
|
function buildWorktreePrompt(issue, testRunner) {
|
|
558
648
|
const testBlock = buildTestInstructions(testRunner ?? null);
|
|
559
649
|
const readmeBlock = buildReadmeInstructions();
|
|
@@ -586,21 +676,26 @@ ${testBlock}${readmeBlock}
|
|
|
586
676
|
- Run whichever validation scripts exist (e.g., \`npm run lint\`, \`npm run typecheck\`).
|
|
587
677
|
- Fix any errors before proceeding.
|
|
588
678
|
|
|
589
|
-
3. **Commit
|
|
590
|
-
|
|
679
|
+
3. **Commit**: Make atomic commits with conventional commit messages.
|
|
680
|
+
**Branch name must be in English.** The branch was pre-created with an auto-generated name.
|
|
681
|
+
If that name contains non-English words, rename it before committing:
|
|
682
|
+
\`git branch -m <current-name> feat/${issue.id.toLowerCase()}-short-english-slug\`
|
|
683
|
+
Do NOT push \u2014 the caller handles pushing.
|
|
591
684
|
**IMPORTANT \u2014 Language rules:**
|
|
592
685
|
- All commit messages MUST be in English.
|
|
593
686
|
- Use conventional commits format: \`feat: ...\`, \`fix: ...\`, \`refactor: ...\`, \`chore: ...\`
|
|
594
687
|
|
|
595
|
-
4. **
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
688
|
+
4. **Write manifest**: Create \`.lisa-manifest.json\` in the **current directory** with JSON:
|
|
689
|
+
\`\`\`json
|
|
690
|
+
{"branch": "<final English branch name>", "prTitle": "<English PR title, conventional commit format>"}
|
|
691
|
+
\`\`\`
|
|
692
|
+
Do NOT commit this file.
|
|
599
693
|
|
|
600
694
|
## Rules
|
|
601
695
|
|
|
602
|
-
- **ALL git commits, PR titles, and PR descriptions MUST be in English.**
|
|
696
|
+
- **ALL git commits, branch names, PR titles, and PR descriptions MUST be in English.**
|
|
603
697
|
- The issue description may be in any language \u2014 read it for context but write all code artifacts in English.
|
|
698
|
+
- Do NOT push \u2014 the caller handles that.
|
|
604
699
|
- Do NOT install new dependencies unless the issue explicitly requires it.
|
|
605
700
|
- If you get stuck or the issue is unclear, STOP and explain why.
|
|
606
701
|
- One issue only. Do not pick up additional issues.
|
|
@@ -616,6 +711,7 @@ function buildBranchPrompt(issue, config2, testRunner) {
|
|
|
616
711
|
const baseBranchInstruction = config2.repos.length > 0 ? "From the repo's base branch (listed above)" : `From \`${config2.base_branch}\``;
|
|
617
712
|
const testBlock = buildTestInstructions(testRunner ?? null);
|
|
618
713
|
const readmeBlock = buildReadmeInstructions();
|
|
714
|
+
const manifestPath = join(workspace, ".lisa-manifest.json");
|
|
619
715
|
return `You are an autonomous implementation agent. Your job is to implement a single
|
|
620
716
|
issue, validate it, commit, and push the branch.
|
|
621
717
|
|
|
@@ -635,8 +731,10 @@ ${issue.description}
|
|
|
635
731
|
${repoEntries}
|
|
636
732
|
- If it references multiple repos, pick the PRIMARY one (the one with the most files listed).
|
|
637
733
|
|
|
638
|
-
2. **Create a branch**: ${baseBranchInstruction}, create a branch
|
|
639
|
-
|
|
734
|
+
2. **Create a branch**: ${baseBranchInstruction}, create a branch with an **English** slug:
|
|
735
|
+
\`feat/${issue.id.toLowerCase()}-short-english-description\`
|
|
736
|
+
The description MUST be in English \u2014 translate or summarize the issue title if it's in another language.
|
|
737
|
+
Example: "Implementar rate limiting na API" \u2192 \`feat/${issue.id.toLowerCase()}-add-rate-limiting-to-api\`
|
|
640
738
|
|
|
641
739
|
3. **Implement**: Follow the issue description exactly:
|
|
642
740
|
- Read all relevant files listed in the description first (if present)
|
|
@@ -655,10 +753,11 @@ ${testBlock}${readmeBlock}
|
|
|
655
753
|
- All commit messages MUST be in English.
|
|
656
754
|
- Use conventional commits format: \`feat: ...\`, \`fix: ...\`, \`refactor: ...\`, \`chore: ...\`
|
|
657
755
|
|
|
658
|
-
6. **
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
756
|
+
6. **Write manifest**: Before finishing, create \`${manifestPath}\` with JSON:
|
|
757
|
+
\`\`\`json
|
|
758
|
+
{"repoPath": "<absolute path to this repo>", "branch": "<branch name>", "prTitle": "<English PR title, conventional commit format>"}
|
|
759
|
+
\`\`\`
|
|
760
|
+
Do NOT commit this file.
|
|
662
761
|
|
|
663
762
|
## Rules
|
|
664
763
|
|
|
@@ -1677,6 +1776,22 @@ function cleanupPrTitle(cwd) {
|
|
|
1677
1776
|
} catch {
|
|
1678
1777
|
}
|
|
1679
1778
|
}
|
|
1779
|
+
var MANIFEST_FILE = ".lisa-manifest.json";
|
|
1780
|
+
function readLisaManifest(dir) {
|
|
1781
|
+
const manifestPath = join7(dir, MANIFEST_FILE);
|
|
1782
|
+
if (!existsSync6(manifestPath)) return null;
|
|
1783
|
+
try {
|
|
1784
|
+
return JSON.parse(readFileSync5(manifestPath, "utf-8").trim());
|
|
1785
|
+
} catch {
|
|
1786
|
+
return null;
|
|
1787
|
+
}
|
|
1788
|
+
}
|
|
1789
|
+
function cleanupManifest(dir) {
|
|
1790
|
+
try {
|
|
1791
|
+
unlinkSync4(join7(dir, MANIFEST_FILE));
|
|
1792
|
+
} catch {
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1680
1795
|
function installSignalHandlers() {
|
|
1681
1796
|
const cleanup = async (signal) => {
|
|
1682
1797
|
if (shuttingDown) {
|
|
@@ -1942,6 +2057,9 @@ async function runTestValidation(cwd) {
|
|
|
1942
2057
|
}
|
|
1943
2058
|
}
|
|
1944
2059
|
async function runWorktreeSession(config2, issue, logFile, session, models) {
|
|
2060
|
+
if (config2.repos.length > 1) {
|
|
2061
|
+
return runWorktreeMultiRepoSession(config2, issue, logFile, session, models);
|
|
2062
|
+
}
|
|
1945
2063
|
const workspace = resolve5(config2.workspace);
|
|
1946
2064
|
const repoPath = determineRepoPath(config2.repos, issue, workspace) ?? workspace;
|
|
1947
2065
|
const defaultBranch = resolveBaseBranch(config2, repoPath);
|
|
@@ -2026,17 +2144,33 @@ ${result.output}
|
|
|
2026
2144
|
await cleanupWorktree(repoPath, worktreePath);
|
|
2027
2145
|
return { success: false, providerUsed: result.providerUsed, prUrls: [], fallback: result };
|
|
2028
2146
|
}
|
|
2147
|
+
const manifest = readLisaManifest(worktreePath);
|
|
2148
|
+
let effectiveBranch = branchName;
|
|
2149
|
+
if (manifest?.branch && manifest.branch !== branchName) {
|
|
2150
|
+
log(`Renaming branch to English name: ${manifest.branch}`);
|
|
2151
|
+
try {
|
|
2152
|
+
await execa3("git", ["branch", "-m", branchName, manifest.branch], { cwd: worktreePath });
|
|
2153
|
+
effectiveBranch = manifest.branch;
|
|
2154
|
+
ok(`Branch renamed to ${effectiveBranch}`);
|
|
2155
|
+
} catch (err) {
|
|
2156
|
+
warn(
|
|
2157
|
+
`Branch rename failed, using original: ${err instanceof Error ? err.message : String(err)}`
|
|
2158
|
+
);
|
|
2159
|
+
}
|
|
2160
|
+
}
|
|
2029
2161
|
try {
|
|
2030
|
-
await execa3("git", ["push", "-u", "origin",
|
|
2162
|
+
await execa3("git", ["push", "-u", "origin", effectiveBranch], { cwd: worktreePath });
|
|
2031
2163
|
} catch (err) {
|
|
2032
2164
|
error(
|
|
2033
2165
|
`Failed to push branch to remote: ${err instanceof Error ? err.message : String(err)}`
|
|
2034
2166
|
);
|
|
2167
|
+
cleanupManifest(worktreePath);
|
|
2035
2168
|
await cleanupWorktree(repoPath, worktreePath);
|
|
2036
2169
|
return { success: false, providerUsed: result.providerUsed, prUrls: [], fallback: result };
|
|
2037
2170
|
}
|
|
2038
|
-
const prTitle = readPrTitle(worktreePath) ?? issue.title;
|
|
2171
|
+
const prTitle = manifest?.prTitle ?? readPrTitle(worktreePath) ?? issue.title;
|
|
2039
2172
|
cleanupPrTitle(worktreePath);
|
|
2173
|
+
cleanupManifest(worktreePath);
|
|
2040
2174
|
const prUrls = [];
|
|
2041
2175
|
try {
|
|
2042
2176
|
const repoInfo = await getRepoInfo(worktreePath);
|
|
@@ -2044,7 +2178,7 @@ ${result.output}
|
|
|
2044
2178
|
{
|
|
2045
2179
|
owner: repoInfo.owner,
|
|
2046
2180
|
repo: repoInfo.repo,
|
|
2047
|
-
head:
|
|
2181
|
+
head: effectiveBranch,
|
|
2048
2182
|
base: defaultBranch,
|
|
2049
2183
|
title: prTitle,
|
|
2050
2184
|
body: buildPrBody(issue, result.providerUsed)
|
|
@@ -2060,8 +2194,98 @@ ${result.output}
|
|
|
2060
2194
|
ok(`Session ${session} complete for ${issue.id}`);
|
|
2061
2195
|
return { success: true, providerUsed: result.providerUsed, prUrls, fallback: result };
|
|
2062
2196
|
}
|
|
2197
|
+
async function runWorktreeMultiRepoSession(config2, issue, logFile, session, models) {
|
|
2198
|
+
const workspace = resolve5(config2.workspace);
|
|
2199
|
+
cleanupManifest(workspace);
|
|
2200
|
+
const prompt = buildWorktreeMultiRepoPrompt(issue, config2);
|
|
2201
|
+
log(`Multi-repo worktree session for ${issue.id} (agent selects repo and branch name)`);
|
|
2202
|
+
log(`Implementing (agent selects repo)... (log: ${logFile})`);
|
|
2203
|
+
initLogFile(logFile);
|
|
2204
|
+
const result = await runWithFallback(models, prompt, {
|
|
2205
|
+
logFile,
|
|
2206
|
+
cwd: workspace,
|
|
2207
|
+
guardrailsDir: workspace,
|
|
2208
|
+
issueId: issue.id,
|
|
2209
|
+
overseer: config2.overseer
|
|
2210
|
+
});
|
|
2211
|
+
try {
|
|
2212
|
+
appendFileSync6(
|
|
2213
|
+
logFile,
|
|
2214
|
+
`
|
|
2215
|
+
${"=".repeat(80)}
|
|
2216
|
+
Provider used: ${result.providerUsed}
|
|
2217
|
+
Full output:
|
|
2218
|
+
${result.output}
|
|
2219
|
+
`
|
|
2220
|
+
);
|
|
2221
|
+
} catch {
|
|
2222
|
+
}
|
|
2223
|
+
if (!result.success) {
|
|
2224
|
+
error(`Session ${session} failed for ${issue.id}. Check ${logFile}`);
|
|
2225
|
+
cleanupManifest(workspace);
|
|
2226
|
+
return { success: false, providerUsed: result.providerUsed, prUrls: [], fallback: result };
|
|
2227
|
+
}
|
|
2228
|
+
const manifest = readLisaManifest(workspace);
|
|
2229
|
+
if (!manifest?.repoPath || !manifest.branch) {
|
|
2230
|
+
error(
|
|
2231
|
+
`Agent did not produce a valid .lisa-manifest.json (requires repoPath + branch) for ${issue.id}. Aborting.`
|
|
2232
|
+
);
|
|
2233
|
+
cleanupManifest(workspace);
|
|
2234
|
+
return { success: false, providerUsed: result.providerUsed, prUrls: [], fallback: result };
|
|
2235
|
+
}
|
|
2236
|
+
ok(`Provider chose repo: ${manifest.repoPath}, branch: ${manifest.branch}`);
|
|
2237
|
+
const worktreePath = join7(manifest.repoPath, ".worktrees", manifest.branch);
|
|
2238
|
+
const baseBranch = resolveBaseBranch(config2, manifest.repoPath);
|
|
2239
|
+
const hasWorktree = existsSync6(worktreePath);
|
|
2240
|
+
const effectiveCwd = hasWorktree ? worktreePath : manifest.repoPath;
|
|
2241
|
+
if (!hasWorktree) {
|
|
2242
|
+
warn(`Worktree not found at ${worktreePath} \u2014 using repo root for git operations`);
|
|
2243
|
+
}
|
|
2244
|
+
const testsPassed = await runTestValidation(effectiveCwd);
|
|
2245
|
+
if (!testsPassed) {
|
|
2246
|
+
error(`Tests failed for ${issue.id}. Blocking PR creation.`);
|
|
2247
|
+
if (hasWorktree) await cleanupWorktree(manifest.repoPath, worktreePath);
|
|
2248
|
+
cleanupManifest(workspace);
|
|
2249
|
+
return { success: false, providerUsed: result.providerUsed, prUrls: [], fallback: result };
|
|
2250
|
+
}
|
|
2251
|
+
try {
|
|
2252
|
+
await execa3("git", ["push", "-u", "origin", manifest.branch], { cwd: effectiveCwd });
|
|
2253
|
+
} catch (err) {
|
|
2254
|
+
error(
|
|
2255
|
+
`Failed to push branch to remote: ${err instanceof Error ? err.message : String(err)}`
|
|
2256
|
+
);
|
|
2257
|
+
if (hasWorktree) await cleanupWorktree(manifest.repoPath, worktreePath);
|
|
2258
|
+
cleanupManifest(workspace);
|
|
2259
|
+
return { success: false, providerUsed: result.providerUsed, prUrls: [], fallback: result };
|
|
2260
|
+
}
|
|
2261
|
+
const prTitle = manifest.prTitle ?? issue.title;
|
|
2262
|
+
const prUrls = [];
|
|
2263
|
+
try {
|
|
2264
|
+
const repoInfo = await getRepoInfo(effectiveCwd);
|
|
2265
|
+
const pr = await createPullRequest(
|
|
2266
|
+
{
|
|
2267
|
+
owner: repoInfo.owner,
|
|
2268
|
+
repo: repoInfo.repo,
|
|
2269
|
+
head: manifest.branch,
|
|
2270
|
+
base: baseBranch,
|
|
2271
|
+
title: prTitle,
|
|
2272
|
+
body: buildPrBody(issue, result.providerUsed)
|
|
2273
|
+
},
|
|
2274
|
+
config2.github
|
|
2275
|
+
);
|
|
2276
|
+
ok(`PR created: ${pr.html_url}`);
|
|
2277
|
+
prUrls.push(pr.html_url);
|
|
2278
|
+
} catch (err) {
|
|
2279
|
+
error(`Failed to create PR: ${err instanceof Error ? err.message : String(err)}`);
|
|
2280
|
+
}
|
|
2281
|
+
cleanupManifest(workspace);
|
|
2282
|
+
if (hasWorktree) await cleanupWorktree(manifest.repoPath, worktreePath);
|
|
2283
|
+
ok(`Session ${session} complete for ${issue.id}`);
|
|
2284
|
+
return { success: true, providerUsed: result.providerUsed, prUrls, fallback: result };
|
|
2285
|
+
}
|
|
2063
2286
|
async function runBranchSession(config2, issue, logFile, session, models) {
|
|
2064
2287
|
const workspace = resolve5(config2.workspace);
|
|
2288
|
+
cleanupManifest(workspace);
|
|
2065
2289
|
const testRunner = detectTestRunner(workspace);
|
|
2066
2290
|
if (testRunner) {
|
|
2067
2291
|
log(`Detected test runner: ${testRunner}`);
|
|
@@ -2118,20 +2342,27 @@ ${result.output}
|
|
|
2118
2342
|
const testsPassed = await runTestValidation(workspace);
|
|
2119
2343
|
if (!testsPassed) {
|
|
2120
2344
|
error(`Tests failed for ${issue.id}. Blocking PR creation.`);
|
|
2345
|
+
cleanupManifest(workspace);
|
|
2121
2346
|
return { success: false, providerUsed: result.providerUsed, prUrls: [], fallback: result };
|
|
2122
2347
|
}
|
|
2123
|
-
const
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2348
|
+
const manifest = readLisaManifest(workspace);
|
|
2349
|
+
let detected;
|
|
2350
|
+
if (manifest?.repoPath && manifest.branch) {
|
|
2351
|
+
ok(`Using manifest: repo=${manifest.repoPath}, branch=${manifest.branch}`);
|
|
2352
|
+
detected = [{ repoPath: manifest.repoPath, branch: manifest.branch }];
|
|
2353
|
+
} else {
|
|
2354
|
+
if (manifest) {
|
|
2355
|
+
warn(`Manifest found but missing repoPath or branch \u2014 falling back to detection`);
|
|
2356
|
+
}
|
|
2357
|
+
detected = await detectFeatureBranches(config2.repos, issue.id, workspace, config2.base_branch);
|
|
2358
|
+
}
|
|
2359
|
+
cleanupManifest(workspace);
|
|
2129
2360
|
if (detected.length === 0) {
|
|
2130
2361
|
error(`Could not detect feature branch for ${issue.id} \u2014 skipping PR creation`);
|
|
2131
2362
|
ok(`Session ${session} complete for ${issue.id}`);
|
|
2132
2363
|
return { success: true, providerUsed: result.providerUsed, prUrls: [], fallback: result };
|
|
2133
2364
|
}
|
|
2134
|
-
const prTitle = readPrTitle(workspace) ?? issue.title;
|
|
2365
|
+
const prTitle = manifest?.prTitle ?? readPrTitle(workspace) ?? issue.title;
|
|
2135
2366
|
cleanupPrTitle(workspace);
|
|
2136
2367
|
const prUrls = [];
|
|
2137
2368
|
for (const { repoPath, branch } of detected) {
|
|
@@ -2290,8 +2521,8 @@ var status = defineCommand({
|
|
|
2290
2521
|
console.log(` In progress: ${pc2.bold(config2.source_config.in_progress)}`);
|
|
2291
2522
|
console.log(` Done: ${pc2.bold(config2.source_config.done)}`);
|
|
2292
2523
|
console.log(` Logs: ${pc2.dim(config2.logs.dir)}`);
|
|
2293
|
-
const { readdirSync: readdirSync2, existsSync:
|
|
2294
|
-
if (
|
|
2524
|
+
const { readdirSync: readdirSync2, existsSync: existsSync8 } = await import("fs");
|
|
2525
|
+
if (existsSync8(config2.logs.dir)) {
|
|
2295
2526
|
const logs = readdirSync2(config2.logs.dir).filter((f) => f.endsWith(".log"));
|
|
2296
2527
|
console.log(`
|
|
2297
2528
|
${pc2.cyan("Sessions:")} ${logs.length} log file(s) found`);
|
|
@@ -2526,12 +2757,12 @@ async function detectGitHubMethod() {
|
|
|
2526
2757
|
}
|
|
2527
2758
|
async function detectGitRepos() {
|
|
2528
2759
|
const cwd = process.cwd();
|
|
2529
|
-
if (
|
|
2760
|
+
if (existsSync7(join8(cwd, ".git"))) {
|
|
2530
2761
|
clack.log.info(`Detected git repository in current directory.`);
|
|
2531
2762
|
return [];
|
|
2532
2763
|
}
|
|
2533
2764
|
const entries = readdirSync(cwd, { withFileTypes: true });
|
|
2534
|
-
const gitDirs = entries.filter((e) => e.isDirectory() &&
|
|
2765
|
+
const gitDirs = entries.filter((e) => e.isDirectory() && existsSync7(join8(cwd, e.name, ".git"))).map((e) => e.name);
|
|
2535
2766
|
if (gitDirs.length === 0) {
|
|
2536
2767
|
return [];
|
|
2537
2768
|
}
|