@tarcisiopgs/lisa 1.21.2 → 1.22.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.
Files changed (2) hide show
  1. package/dist/index.js +120 -91
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -642,8 +642,7 @@ var AiderProvider = class {
642
642
  kanbanEmitter.emit(
643
643
  "issue:output",
644
644
  opts.issueId,
645
- `${`$ aider --message-file --yes-always ${modelFlag || "(default model)"}
646
- `.trim()}
645
+ `$ aider --message-file --yes-always ${modelFlag || "(default model)"} <prompt: ${prompt.length} chars>
647
646
  `
648
647
  );
649
648
  }
@@ -746,8 +745,12 @@ var ClaudeProvider = class {
746
745
  const command = `claude ${flags.join(" ")} "$(cat '${promptFile}')"`;
747
746
  log(`[claude] Running: claude ${flags.join(" ")}`.trim());
748
747
  if (opts.issueId) {
749
- kanbanEmitter.emit("issue:output", opts.issueId, `$ claude ${flags.join(" ")}
750
- `);
748
+ kanbanEmitter.emit(
749
+ "issue:output",
750
+ opts.issueId,
751
+ `$ claude ${flags.join(" ")} <prompt: ${prompt.length} chars>
752
+ `
753
+ );
751
754
  }
752
755
  const spawnEnv = { ...process.env, ...opts.env, CLAUDECODE: void 0 };
753
756
  const isNestedInClaude = Boolean(process.env.CLAUDECODE);
@@ -858,8 +861,8 @@ var CodexProvider = class {
858
861
  kanbanEmitter.emit(
859
862
  "issue:output",
860
863
  opts.issueId,
861
- `$ codex exec --dangerously-bypass-approvals-and-sandbox --ephemeral ${modelFlag || "(default model)"}
862
- `.trim() + "\n"
864
+ `$ codex exec --dangerously-bypass-approvals-and-sandbox --ephemeral ${modelFlag || "(default model)"} <prompt: ${prompt.length} chars>
865
+ `
863
866
  );
864
867
  }
865
868
  const { proc, isPty } = spawnWithPty(command, {
@@ -961,8 +964,7 @@ var CopilotProvider = class {
961
964
  kanbanEmitter.emit(
962
965
  "issue:output",
963
966
  opts.issueId,
964
- `${`$ copilot --allow-all ${modelFlag || "(default model)"} -p
965
- `.trim()}
967
+ `$ copilot --allow-all ${modelFlag || "(default model)"} -p <prompt: ${prompt.length} chars>
966
968
  `
967
969
  );
968
970
  }
@@ -1083,8 +1085,8 @@ var CursorProvider = class {
1083
1085
  kanbanEmitter.emit(
1084
1086
  "issue:output",
1085
1087
  opts.issueId,
1086
- `$ ${bin} -p --output-format text --force ${modelFlag || "(default model)"}
1087
- `.trim() + "\n"
1088
+ `$ ${bin} -p --output-format text --force ${modelFlag || "(default model)"} <prompt: ${prompt.length} chars>
1089
+ `
1088
1090
  );
1089
1091
  }
1090
1092
  const { proc, isPty } = spawnWithPty(command, {
@@ -1185,8 +1187,7 @@ var GeminiProvider = class {
1185
1187
  kanbanEmitter.emit(
1186
1188
  "issue:output",
1187
1189
  opts.issueId,
1188
- `${`$ gemini --yolo ${modelFlag || "(default model)"} -p
1189
- `.trim()}
1190
+ `$ gemini --yolo ${modelFlag || "(default model)"} -p <prompt: ${prompt.length} chars>
1190
1191
  `
1191
1192
  );
1192
1193
  }
@@ -1290,8 +1291,7 @@ var GooseProvider = class {
1290
1291
  kanbanEmitter.emit(
1291
1292
  "issue:output",
1292
1293
  opts.issueId,
1293
- `${`$ goose run ${providerFlag} ${modelFlag || "(default model)"} --text
1294
- `.trim()}
1294
+ `$ goose run ${providerFlag} ${modelFlag || "(default model)"} --text <prompt: ${prompt.length} chars>
1295
1295
  `
1296
1296
  );
1297
1297
  }
@@ -1392,8 +1392,7 @@ var OpenCodeProvider = class {
1392
1392
  kanbanEmitter.emit(
1393
1393
  "issue:output",
1394
1394
  opts.issueId,
1395
- `${`$ opencode run ${modelFlag || "(default model)"}
1396
- `.trim()}
1395
+ `$ opencode run ${modelFlag || "(default model)"} <prompt: ${prompt.length} chars>
1397
1396
  `
1398
1397
  );
1399
1398
  }
@@ -4995,7 +4994,10 @@ Do NOT use interactive skills, ask clarifying questions, or wait for user input.
4995
4994
 
4996
4995
  You are already inside the correct repository worktree on the correct branch.
4997
4996
  Do NOT create a new branch \u2014 just work on the current one.
4998
-
4997
+ ${cwd ? `
4998
+ **Working directory:** \`${cwd}\`
4999
+ All file paths are relative to this directory. Use this as the base for any absolute paths.
5000
+ ` : ""}
4999
5001
  ## Issue
5000
5002
 
5001
5003
  - **ID:** ${issue2.id}
@@ -5146,7 +5148,10 @@ Do NOT use interactive skills, ask clarifying questions, or wait for user input.
5146
5148
 
5147
5149
  You are working inside a git worktree that was automatically created for this task.
5148
5150
  Work on the current branch \u2014 it was created for you.
5149
-
5151
+ ${repoPath ? `
5152
+ **Working directory:** \`${repoPath}\`
5153
+ All file paths are relative to this directory. Use this as the base for any absolute paths.
5154
+ ` : ""}
5150
5155
  ## Issue
5151
5156
 
5152
5157
  - **ID:** ${issue2.id}
@@ -5285,7 +5290,10 @@ Use this context if the current step depends on changes from previous steps.
5285
5290
 
5286
5291
  You are working inside a git worktree that was automatically created for this task.
5287
5292
  Work on the current branch \u2014 it was created for you.
5288
-
5293
+ ${cwd ? `
5294
+ **Working directory:** \`${cwd}\`
5295
+ All file paths are relative to this directory. Use this as the base for any absolute paths.
5296
+ ` : ""}
5289
5297
  ## Issue
5290
5298
 
5291
5299
  - **ID:** ${issue2.id}
@@ -5661,7 +5669,8 @@ function registerCleanup() {
5661
5669
  }
5662
5670
 
5663
5671
  // src/loop/manifest.ts
5664
- import { existsSync as existsSync8, readFileSync as readFileSync8, unlinkSync } from "fs";
5672
+ import { existsSync as existsSync8, readdirSync as readdirSync2, readFileSync as readFileSync8, rmdirSync, unlinkSync } from "fs";
5673
+ import { dirname as dirname2 } from "path";
5665
5674
  function readLisaManifest(cwd, issueId) {
5666
5675
  const manifestPath = getManifestPath(cwd, issueId);
5667
5676
  if (!existsSync8(manifestPath)) return null;
@@ -5706,89 +5715,108 @@ function readPlanFile(filePath) {
5706
5715
  return null;
5707
5716
  }
5708
5717
  }
5718
+ function cleanupPlanFile(filePath) {
5719
+ try {
5720
+ unlinkSync(filePath);
5721
+ } catch {
5722
+ }
5723
+ try {
5724
+ const dir = dirname2(filePath);
5725
+ if (existsSync8(dir) && readdirSync2(dir).length === 0) {
5726
+ rmdirSync(dir);
5727
+ }
5728
+ } catch {
5729
+ }
5730
+ }
5709
5731
 
5710
5732
  // src/loop/multi-repo-session.ts
5711
- import { appendFileSync as appendFileSync10, unlinkSync as unlinkSync2 } from "fs";
5733
+ import { appendFileSync as appendFileSync10 } from "fs";
5712
5734
  import { resolve as resolve9 } from "path";
5713
5735
  async function runWorktreeMultiRepoSession(config2, issue2, logFile, session, models) {
5714
5736
  const workspace = resolve9(config2.workspace);
5715
5737
  const planPath = getPlanPath(workspace, issue2.id);
5716
- try {
5717
- unlinkSync2(planPath);
5718
- } catch {
5719
- }
5720
5738
  initLogFile(logFile);
5721
5739
  kanbanEmitter.emit("issue:log-file", issue2.id, logFile);
5722
- startSpinner(`${issue2.id} \u2014 analyzing issue...`);
5723
- log(`Multi-repo planning phase for ${issue2.id}`);
5724
- const globalContextMd = readContext(workspace);
5725
- const planPrompt = buildPlanningPrompt(issue2, config2, planPath, globalContextMd);
5726
- const planResult = await runWithFallback(models, planPrompt, {
5727
- logFile,
5728
- cwd: workspace,
5729
- guardrailsDir: workspace,
5730
- issueId: issue2.id,
5731
- overseer: config2.overseer,
5732
- sessionTimeout: config2.loop.session_timeout,
5733
- outputStallTimeout: config2.loop.output_stall_timeout,
5734
- onProcess: (pid) => {
5735
- activeProviderPids.set(issue2.id, pid);
5736
- },
5737
- shouldAbort: () => userKilledSet.has(issue2.id) || userSkippedSet.has(issue2.id)
5738
- });
5739
- stopSpinner();
5740
- try {
5741
- appendFileSync10(
5740
+ const cachedPlan = readPlanFile(planPath);
5741
+ let planProviderUsed = models[0]?.provider ?? "claude";
5742
+ let planFallback = null;
5743
+ let sortedSteps;
5744
+ if (cachedPlan?.steps && cachedPlan.steps.length > 0) {
5745
+ sortedSteps = [...cachedPlan.steps].sort((a, b) => a.order - b.order);
5746
+ ok(
5747
+ `Reusing cached plan for ${issue2.id}: ${sortedSteps.length} step(s) \u2014 ${sortedSteps.map((s) => s.repoPath).join(" \u2192 ")}`
5748
+ );
5749
+ } else {
5750
+ startSpinner(`${issue2.id} \u2014 analyzing issue...`);
5751
+ log(`Multi-repo planning phase for ${issue2.id}`);
5752
+ const globalContextMd = readContext(workspace);
5753
+ const planPrompt = buildPlanningPrompt(issue2, config2, planPath, globalContextMd);
5754
+ const planResult = await runWithFallback(models, planPrompt, {
5742
5755
  logFile,
5743
- `
5756
+ cwd: workspace,
5757
+ guardrailsDir: workspace,
5758
+ issueId: issue2.id,
5759
+ overseer: config2.overseer,
5760
+ sessionTimeout: config2.loop.session_timeout,
5761
+ outputStallTimeout: config2.loop.output_stall_timeout,
5762
+ onProcess: (pid) => {
5763
+ activeProviderPids.set(issue2.id, pid);
5764
+ },
5765
+ shouldAbort: () => userKilledSet.has(issue2.id) || userSkippedSet.has(issue2.id)
5766
+ });
5767
+ stopSpinner();
5768
+ planProviderUsed = planResult.providerUsed;
5769
+ planFallback = planResult;
5770
+ try {
5771
+ appendFileSync10(
5772
+ logFile,
5773
+ `
5744
5774
  ${"=".repeat(80)}
5745
5775
  Planning phase \u2014 provider: ${planResult.providerUsed}
5746
5776
  ${planResult.output}
5747
5777
  `
5748
- );
5749
- } catch {
5750
- }
5751
- if (!planResult.success) {
5752
- error(`Planning phase failed for ${issue2.id}. Check ${logFile}`);
5753
- try {
5754
- unlinkSync2(planPath);
5778
+ );
5755
5779
  } catch {
5756
5780
  }
5757
- activeProviderPids.delete(issue2.id);
5758
- return {
5759
- success: false,
5760
- providerUsed: planResult.providerUsed,
5761
- prUrls: [],
5762
- fallback: planResult
5763
- };
5764
- }
5765
- const plan = readPlanFile(planPath);
5766
- if (!plan?.steps || plan.steps.length === 0) {
5767
- error(`Agent did not produce a valid execution plan for ${issue2.id}. Aborting.`);
5768
- try {
5769
- unlinkSync2(planPath);
5770
- } catch {
5781
+ if (!planResult.success) {
5782
+ error(`Planning phase failed for ${issue2.id}. Check ${logFile}`);
5783
+ cleanupPlanFile(planPath);
5784
+ activeProviderPids.delete(issue2.id);
5785
+ return {
5786
+ success: false,
5787
+ providerUsed: planResult.providerUsed,
5788
+ prUrls: [],
5789
+ fallback: planResult
5790
+ };
5771
5791
  }
5772
- activeProviderPids.delete(issue2.id);
5773
- return {
5774
- success: false,
5775
- providerUsed: planResult.providerUsed,
5776
- prUrls: [],
5777
- fallback: planResult
5778
- };
5779
- }
5780
- const sortedSteps = [...plan.steps].sort((a, b) => a.order - b.order);
5781
- ok(
5782
- `Plan produced ${sortedSteps.length} step(s): ${sortedSteps.map((s) => s.repoPath).join(" \u2192 ")}`
5783
- );
5784
- try {
5785
- unlinkSync2(planPath);
5786
- } catch {
5792
+ const plan = readPlanFile(planPath);
5793
+ if (!plan?.steps || plan.steps.length === 0) {
5794
+ error(`Agent did not produce a valid execution plan for ${issue2.id}. Aborting.`);
5795
+ cleanupPlanFile(planPath);
5796
+ activeProviderPids.delete(issue2.id);
5797
+ return {
5798
+ success: false,
5799
+ providerUsed: planResult.providerUsed,
5800
+ prUrls: [],
5801
+ fallback: planResult
5802
+ };
5803
+ }
5804
+ sortedSteps = [...plan.steps].sort((a, b) => a.order - b.order);
5805
+ ok(
5806
+ `Plan produced ${sortedSteps.length} step(s): ${sortedSteps.map((s) => s.repoPath).join(" \u2192 ")}`
5807
+ );
5787
5808
  }
5809
+ const defaultFallback = planFallback ?? {
5810
+ success: true,
5811
+ output: "",
5812
+ duration: 0,
5813
+ providerUsed: planProviderUsed,
5814
+ attempts: []
5815
+ };
5788
5816
  const prUrls = [];
5789
5817
  const previousResults = [];
5790
- let lastFallback = planResult;
5791
- let lastProvider = planResult.providerUsed;
5818
+ let lastFallback = defaultFallback;
5819
+ let lastProvider = planProviderUsed;
5792
5820
  for (const [i, step] of sortedSteps.entries()) {
5793
5821
  const stepNum = i + 1;
5794
5822
  const isLastStep = i === sortedSteps.length - 1;
@@ -5826,6 +5854,7 @@ ${planResult.output}
5826
5854
  });
5827
5855
  }
5828
5856
  activeProviderPids.delete(issue2.id);
5857
+ cleanupPlanFile(planPath);
5829
5858
  ok(`Session ${session} complete for ${issue2.id} \u2014 ${prUrls.length} PR(s) created`);
5830
5859
  return { success: true, providerUsed: lastProvider, prUrls, fallback: lastFallback };
5831
5860
  }
@@ -6531,13 +6560,13 @@ async function getChangedFiles(repoPath, baseBranch, dependencyBranch) {
6531
6560
  }
6532
6561
 
6533
6562
  // src/loop/branch-session.ts
6534
- import { appendFileSync as appendFileSync12, unlinkSync as unlinkSync3 } from "fs";
6563
+ import { appendFileSync as appendFileSync12, unlinkSync as unlinkSync2 } from "fs";
6535
6564
  import { resolve as resolve12 } from "path";
6536
6565
  async function runBranchSession(config2, issue2, logFile, session, models) {
6537
6566
  const workspace = resolve12(config2.workspace);
6538
6567
  const manifestPath = getManifestPath(workspace, issue2.id);
6539
6568
  try {
6540
- unlinkSync3(manifestPath);
6569
+ unlinkSync2(manifestPath);
6541
6570
  } catch {
6542
6571
  }
6543
6572
  const testRunner = detectTestRunner(workspace);
@@ -6637,7 +6666,7 @@ ${result.output}
6637
6666
  }
6638
6667
  const manifest = readManifestFile(manifestPath);
6639
6668
  try {
6640
- unlinkSync3(manifestPath);
6669
+ unlinkSync2(manifestPath);
6641
6670
  } catch {
6642
6671
  }
6643
6672
  let prUrl = manifest?.prUrl;
@@ -7071,7 +7100,7 @@ async function runLoop(config2, opts) {
7071
7100
 
7072
7101
  // src/session/kanban-persistence.ts
7073
7102
  import { existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync9, renameSync, writeFileSync as writeFileSync12 } from "fs";
7074
- import { dirname as dirname2 } from "path";
7103
+ import { dirname as dirname3 } from "path";
7075
7104
  var STATE_VERSION = 1;
7076
7105
  var OUTPUT_TAIL_LINES = 100;
7077
7106
  function resolveCard(card) {
@@ -7224,7 +7253,7 @@ var KanbanPersistence = class {
7224
7253
  }
7225
7254
  flush() {
7226
7255
  this.state.updatedAt = Date.now();
7227
- const dir = dirname2(this.statePath);
7256
+ const dir = dirname3(this.statePath);
7228
7257
  if (!existsSync9(dir)) mkdirSync4(dir, { recursive: true });
7229
7258
  writeFileSync12(this.statePath, JSON.stringify(this.state));
7230
7259
  }
@@ -7415,7 +7444,7 @@ Add them to your ${shell} and run: source ${shell}`));
7415
7444
  });
7416
7445
 
7417
7446
  // src/cli/commands/status.ts
7418
- import { existsSync as existsSync10, readdirSync as readdirSync2 } from "fs";
7447
+ import { existsSync as existsSync10, readdirSync as readdirSync3 } from "fs";
7419
7448
  import { defineCommand as defineCommand7 } from "citty";
7420
7449
  import pc6 from "picocolors";
7421
7450
  var status = defineCommand7({
@@ -7439,7 +7468,7 @@ var status = defineCommand7({
7439
7468
  const logsDir = getLogsDir(process.cwd());
7440
7469
  console.log(` Logs: ${pc6.dim(logsDir)}`);
7441
7470
  if (existsSync10(logsDir)) {
7442
- const logs = readdirSync2(logsDir).filter((f) => f.endsWith(".log"));
7471
+ const logs = readdirSync3(logsDir).filter((f) => f.endsWith(".log"));
7443
7472
  console.log(`
7444
7473
  ${pc6.cyan("Sessions:")} ${logs.length} log file(s) found`);
7445
7474
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tarcisiopgs/lisa",
3
- "version": "1.21.2",
3
+ "version": "1.22.0",
4
4
  "description": "Autonomous issue resolver",
5
5
  "keywords": [
6
6
  "loop",