@tarcisiopgs/lisa 1.15.0 → 1.16.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 CHANGED
@@ -112,7 +112,7 @@ Set the tokens for your chosen source and PR platform:
112
112
  # PR platform
113
113
  GITHUB_TOKEN # GitHub (platform: cli or token)
114
114
  GITLAB_TOKEN # GitLab (platform: gitlab)
115
- BITBUCKET_TOKEN # Bitbucket (platform: bitbucket)
115
+ BITBUCKET_TOKEN # Bitbucket app password (platform: bitbucket)
116
116
  BITBUCKET_USERNAME # Bitbucket username
117
117
 
118
118
  # Issue sources
@@ -125,9 +125,14 @@ PLANE_BASE_URL # optional, defaults to https://api.plane.so
125
125
  GITLAB_TOKEN # source: gitlab-issues
126
126
  GITLAB_BASE_URL # optional, defaults to https://gitlab.com
127
127
  GITHUB_TOKEN # source: github-issues
128
- JIRA_BASE_URL # source: jira
128
+ JIRA_BASE_URL # source: jira (e.g. https://yourorg.atlassian.net)
129
129
  JIRA_EMAIL
130
- JIRA_API_TOKEN
130
+ JIRA_API_TOKEN # generate at id.atlassian.com — expires, regenerate if 401
131
+
132
+ # Aider provider (one of)
133
+ GEMINI_API_KEY
134
+ OPENAI_API_KEY
135
+ ANTHROPIC_API_KEY
131
136
  ```
132
137
 
133
138
  ---
@@ -196,6 +201,22 @@ validation:
196
201
  require_acceptance_criteria: true
197
202
  ```
198
203
 
204
+ ### Source-specific notes
205
+
206
+ **GitHub Issues / GitLab Issues** — `pick_from`, `in_progress`, and `done` are **labels**, not statuses. Make sure `in_progress` differs from `pick_from`; using the same value causes Lisa to re-pick issues that are already being worked on.
207
+
208
+ **Trello** — `team`, `pick_from`, `in_progress`, and `done` are list **names** (not IDs).
209
+
210
+ **Jira** — `team` is your project **key** (e.g. `ENG`). `JIRA_API_TOKEN` is generated at [id.atlassian.com](https://id.atlassian.com) and expires — regenerate if you get 401 errors.
211
+
212
+ **Goose** — `lisa init` asks which backend to use (gemini-cli, anthropic, openai, etc.) and saves it to config. No env vars needed. You can also set `GOOSE_PROVIDER` manually — it takes precedence over the config value.
213
+
214
+ **Aider** — requires a direct LLM API key (`GEMINI_API_KEY`, `OPENAI_API_KEY`, or `ANTHROPIC_API_KEY`). Does not support OAuth or cached credentials.
215
+
216
+ **OpenCode** — if `~/.config/opencode/config.json` contains MCP entries, remove them or set the file to `{}` to prevent OpenCode from hanging on startup.
217
+
218
+ ---
219
+
199
220
  ### Workflow Modes
200
221
 
201
222
  **Branch** — The agent creates a branch in your current checkout. Simple setup, works everywhere.
@@ -3,7 +3,7 @@
3
3
  // src/paths.ts
4
4
  import { createHash } from "crypto";
5
5
  import { existsSync, mkdirSync, readdirSync, statSync, unlinkSync } from "fs";
6
- import { homedir } from "os";
6
+ import { homedir, platform } from "os";
7
7
  import { join, resolve } from "path";
8
8
  var MAX_LOG_FILES = 20;
9
9
  function projectHash(cwd) {
@@ -11,7 +11,14 @@ function projectHash(cwd) {
11
11
  return createHash("sha256").update(absolute).digest("hex").slice(0, 12);
12
12
  }
13
13
  function getCacheDir(cwd) {
14
- const base = process.env.XDG_CACHE_HOME || join(homedir(), ".cache");
14
+ let base;
15
+ if (process.env.XDG_CACHE_HOME) {
16
+ base = process.env.XDG_CACHE_HOME;
17
+ } else if (platform() === "darwin") {
18
+ base = join(homedir(), "Library", "Caches");
19
+ } else {
20
+ base = join(homedir(), ".cache");
21
+ }
15
22
  return join(base, "lisa", projectHash(cwd));
16
23
  }
17
24
  function getLogsDir(cwd) {
@@ -193,7 +193,7 @@ var GitHubIssuesSource = class {
193
193
  const filterLabels = isOrphanDetection ? [config.pick_from] : Array.isArray(config.label) ? config.label : [config.label];
194
194
  const label = filterLabels.map((l) => encodeURIComponent(l)).join(",");
195
195
  const path = `/repos/${owner}/${repo}/issues?labels=${label}&state=open&sort=created&direction=asc&per_page=100`;
196
- const issues = await githubGet(path);
196
+ const issues = (await githubGet(path)).filter((i) => !i.pull_request);
197
197
  if (issues.length === 0) return null;
198
198
  const unblocked = [];
199
199
  const blocked = [];
@@ -333,7 +333,7 @@ var GitHubIssuesSource = class {
333
333
  const labels = Array.isArray(config.label) ? config.label : [config.label];
334
334
  const label = labels.map((l) => encodeURIComponent(l)).join(",");
335
335
  const path = `/repos/${owner}/${repo}/issues?labels=${label}&state=open&sort=created&direction=asc&per_page=100`;
336
- const issues = await githubGet(path);
336
+ const issues = (await githubGet(path)).filter((i) => !i.pull_request);
337
337
  return issues.map((issue) => ({
338
338
  id: makeIssueId(owner, repo, issue.number),
339
339
  title: issue.title,
@@ -448,10 +448,10 @@ var GitLabIssuesSource = class {
448
448
  );
449
449
  const activeBlockers = links.filter((link) => {
450
450
  if (link.link_type === "is_blocked_by") {
451
- return link.source.state !== "closed";
451
+ return link.state !== "closed";
452
452
  }
453
453
  return false;
454
- }).map((link) => link.source.iid);
454
+ }).map((link) => link.iid);
455
455
  if (activeBlockers.length === 0) {
456
456
  unblocked.push(issue2);
457
457
  } else {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  getGuardrailsPath
4
- } from "./chunk-OYQ6TOAG.js";
4
+ } from "./chunk-GZ2ZAQO4.js";
5
5
 
6
6
  // src/session/guardrails.ts
7
7
  import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
@@ -10,8 +10,8 @@ import {
10
10
  guardrailsPath,
11
11
  migrateGuardrails,
12
12
  readGuardrails
13
- } from "./chunk-NXGXGHS3.js";
14
- import "./chunk-OYQ6TOAG.js";
13
+ } from "./chunk-UQPR5OXK.js";
14
+ import "./chunk-GZ2ZAQO4.js";
15
15
  export {
16
16
  appendEntry,
17
17
  appendEntrySync,
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  extractContext,
7
7
  extractErrorType,
8
8
  migrateGuardrails
9
- } from "./chunk-NXGXGHS3.js";
9
+ } from "./chunk-UQPR5OXK.js";
10
10
  import {
11
11
  ensureCacheDir,
12
12
  getLogsDir,
@@ -14,7 +14,7 @@ import {
14
14
  getPlanPath,
15
15
  getPrCachePath,
16
16
  rotateLogFiles
17
- } from "./chunk-OYQ6TOAG.js";
17
+ } from "./chunk-GZ2ZAQO4.js";
18
18
  import {
19
19
  fetchPrFeedback,
20
20
  formatPrFeedbackEntry
@@ -32,7 +32,7 @@ import {
32
32
  ok,
33
33
  setOutputMode,
34
34
  warn
35
- } from "./chunk-WZIPTRJL.js";
35
+ } from "./chunk-ITQEGO5A.js";
36
36
  import {
37
37
  notify,
38
38
  resetTitle,
@@ -53,7 +53,7 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
53
53
  import { resolve } from "path";
54
54
  import { parse, stringify } from "yaml";
55
55
  var DEFAULT_OVERSEER_CONFIG = {
56
- enabled: false,
56
+ enabled: true,
57
57
  check_interval: 30,
58
58
  stuck_threshold: 300
59
59
  };
@@ -378,7 +378,7 @@ async function hasCodeChanges(repoPath, baseBranch) {
378
378
 
379
379
  // src/providers/aider.ts
380
380
  import { execSync } from "child_process";
381
- import { appendFileSync as appendFileSync2, mkdtempSync, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
381
+ import { appendFileSync as appendFileSync2, mkdtempSync, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
382
382
  import { tmpdir } from "os";
383
383
  import { join as join2 } from "path";
384
384
 
@@ -532,7 +532,8 @@ var AIDER_API_KEY_ENV_VARS = [
532
532
  "COHERE_API_KEY",
533
533
  "MISTRAL_API_KEY",
534
534
  "DEEPSEEK_API_KEY",
535
- "AZURE_API_KEY"
535
+ "AZURE_API_KEY",
536
+ "XAI_API_KEY"
536
537
  ];
537
538
  var AiderProvider = class {
538
539
  name = "aider";
@@ -559,7 +560,7 @@ var AiderProvider = class {
559
560
  writeFileSync2(promptFile, prompt, "utf-8");
560
561
  try {
561
562
  const modelFlag = opts.model ? `--model ${opts.model}` : "";
562
- const command = `aider --message "$(cat '${promptFile}')" --yes-always ${modelFlag}`;
563
+ const command = `aider --message-file '${promptFile}' --yes-always ${modelFlag}`;
563
564
  const { proc, isPty } = spawnWithPty(command, {
564
565
  cwd: opts.cwd,
565
566
  env: { ...process.env, ...opts.env }
@@ -613,7 +614,7 @@ var AiderProvider = class {
613
614
  };
614
615
  } finally {
615
616
  try {
616
- unlinkSync(promptFile);
617
+ rmSync2(tmpDir, { recursive: true, force: true });
617
618
  } catch {
618
619
  }
619
620
  }
@@ -622,7 +623,7 @@ var AiderProvider = class {
622
623
 
623
624
  // src/providers/claude.ts
624
625
  import { execSync as execSync2, spawn as spawn2 } from "child_process";
625
- import { appendFileSync as appendFileSync3, mkdtempSync as mkdtempSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "fs";
626
+ import { appendFileSync as appendFileSync3, mkdtempSync as mkdtempSync2, rmSync as rmSync3, writeFileSync as writeFileSync3 } from "fs";
626
627
  import { tmpdir as tmpdir2 } from "os";
627
628
  import { join as join3 } from "path";
628
629
  var ClaudeProvider = class {
@@ -711,7 +712,7 @@ var ClaudeProvider = class {
711
712
  };
712
713
  } finally {
713
714
  try {
714
- unlinkSync2(promptFile);
715
+ rmSync3(tmpDir, { recursive: true, force: true });
715
716
  } catch {
716
717
  }
717
718
  }
@@ -720,14 +721,14 @@ var ClaudeProvider = class {
720
721
 
721
722
  // src/providers/codex.ts
722
723
  import { execSync as execSync3 } from "child_process";
723
- import { appendFileSync as appendFileSync4, mkdtempSync as mkdtempSync3, unlinkSync as unlinkSync3, writeFileSync as writeFileSync4 } from "fs";
724
+ import { appendFileSync as appendFileSync4, mkdtempSync as mkdtempSync3, rmSync as rmSync4, writeFileSync as writeFileSync4 } from "fs";
724
725
  import { tmpdir as tmpdir3 } from "os";
725
726
  import { join as join4 } from "path";
726
727
  var CodexProvider = class {
727
728
  name = "codex";
728
729
  async isAvailable() {
729
730
  try {
730
- execSync3("codex --version", { stdio: "ignore" });
731
+ execSync3("which codex", { stdio: "ignore" });
731
732
  return true;
732
733
  } catch {
733
734
  return false;
@@ -794,7 +795,7 @@ var CodexProvider = class {
794
795
  };
795
796
  } finally {
796
797
  try {
797
- unlinkSync3(promptFile);
798
+ rmSync4(tmpDir, { recursive: true, force: true });
798
799
  } catch {
799
800
  }
800
801
  }
@@ -803,7 +804,7 @@ var CodexProvider = class {
803
804
 
804
805
  // src/providers/copilot.ts
805
806
  import { execSync as execSync4 } from "child_process";
806
- import { appendFileSync as appendFileSync5, mkdtempSync as mkdtempSync4, unlinkSync as unlinkSync4, writeFileSync as writeFileSync5 } from "fs";
807
+ import { appendFileSync as appendFileSync5, mkdtempSync as mkdtempSync4, rmSync as rmSync5, writeFileSync as writeFileSync5 } from "fs";
807
808
  import { tmpdir as tmpdir4 } from "os";
808
809
  import { join as join5 } from "path";
809
810
  var CopilotProvider = class {
@@ -822,7 +823,8 @@ var CopilotProvider = class {
822
823
  const promptFile = join5(tmpDir, "prompt.md");
823
824
  writeFileSync5(promptFile, prompt, "utf-8");
824
825
  try {
825
- const command = `copilot --allow-all -p "$(cat '${promptFile}')"`;
826
+ const modelFlag = opts.model ? `--model ${opts.model}` : "";
827
+ const command = `copilot --allow-all ${modelFlag} -p "$(cat '${promptFile}')"`;
826
828
  const { proc, isPty } = spawnWithPty(command, {
827
829
  cwd: opts.cwd,
828
830
  env: { ...process.env, ...opts.env }
@@ -876,7 +878,7 @@ var CopilotProvider = class {
876
878
  };
877
879
  } finally {
878
880
  try {
879
- unlinkSync4(promptFile);
881
+ rmSync5(tmpDir, { recursive: true, force: true });
880
882
  } catch {
881
883
  }
882
884
  }
@@ -885,13 +887,13 @@ var CopilotProvider = class {
885
887
 
886
888
  // src/providers/cursor.ts
887
889
  import { execSync as execSync5 } from "child_process";
888
- import { appendFileSync as appendFileSync6, mkdtempSync as mkdtempSync5, unlinkSync as unlinkSync5, writeFileSync as writeFileSync6 } from "fs";
890
+ import { appendFileSync as appendFileSync6, mkdtempSync as mkdtempSync5, rmSync as rmSync6, writeFileSync as writeFileSync6 } from "fs";
889
891
  import { tmpdir as tmpdir5 } from "os";
890
892
  import { join as join6 } from "path";
891
893
  function findCursorBinary() {
892
894
  for (const bin of ["agent", "cursor-agent"]) {
893
895
  try {
894
- execSync5(`${bin} --version`, { stdio: "ignore" });
896
+ execSync5(`which ${bin}`, { stdio: "ignore" });
895
897
  return bin;
896
898
  } catch {
897
899
  }
@@ -900,12 +902,17 @@ function findCursorBinary() {
900
902
  }
901
903
  var CursorProvider = class {
902
904
  name = "cursor";
905
+ _bin = void 0;
906
+ resolveBin() {
907
+ if (this._bin === void 0) this._bin = findCursorBinary();
908
+ return this._bin;
909
+ }
903
910
  async isAvailable() {
904
- return findCursorBinary() !== null;
911
+ return this.resolveBin() !== null;
905
912
  }
906
913
  async run(prompt, opts) {
907
914
  const start = Date.now();
908
- const bin = findCursorBinary();
915
+ const bin = this.resolveBin();
909
916
  if (!bin) {
910
917
  return {
911
918
  success: false,
@@ -972,7 +979,7 @@ var CursorProvider = class {
972
979
  };
973
980
  } finally {
974
981
  try {
975
- unlinkSync5(promptFile);
982
+ rmSync6(tmpDir, { recursive: true, force: true });
976
983
  } catch {
977
984
  }
978
985
  }
@@ -981,7 +988,7 @@ var CursorProvider = class {
981
988
 
982
989
  // src/providers/gemini.ts
983
990
  import { execSync as execSync6 } from "child_process";
984
- import { appendFileSync as appendFileSync7, mkdtempSync as mkdtempSync6, unlinkSync as unlinkSync6, writeFileSync as writeFileSync7 } from "fs";
991
+ import { appendFileSync as appendFileSync7, mkdtempSync as mkdtempSync6, rmSync as rmSync7, writeFileSync as writeFileSync7 } from "fs";
985
992
  import { tmpdir as tmpdir6 } from "os";
986
993
  import { join as join7 } from "path";
987
994
  var GEMINI_ERROR_PATTERN = /^Error (executing tool|generating content)/;
@@ -1056,7 +1063,7 @@ var GeminiProvider = class {
1056
1063
  };
1057
1064
  } finally {
1058
1065
  try {
1059
- unlinkSync6(promptFile);
1066
+ rmSync7(tmpDir, { recursive: true, force: true });
1060
1067
  } catch {
1061
1068
  }
1062
1069
  }
@@ -1065,7 +1072,7 @@ var GeminiProvider = class {
1065
1072
 
1066
1073
  // src/providers/goose.ts
1067
1074
  import { execSync as execSync7 } from "child_process";
1068
- import { appendFileSync as appendFileSync8, mkdtempSync as mkdtempSync7, unlinkSync as unlinkSync7, writeFileSync as writeFileSync8 } from "fs";
1075
+ import { appendFileSync as appendFileSync8, mkdtempSync as mkdtempSync7, rmSync as rmSync8, writeFileSync as writeFileSync8 } from "fs";
1069
1076
  import { tmpdir as tmpdir7 } from "os";
1070
1077
  import { join as join8 } from "path";
1071
1078
  var GooseProvider = class {
@@ -1140,7 +1147,7 @@ var GooseProvider = class {
1140
1147
  };
1141
1148
  } finally {
1142
1149
  try {
1143
- unlinkSync7(promptFile);
1150
+ rmSync8(tmpDir, { recursive: true, force: true });
1144
1151
  } catch {
1145
1152
  }
1146
1153
  }
@@ -1149,7 +1156,7 @@ var GooseProvider = class {
1149
1156
 
1150
1157
  // src/providers/opencode.ts
1151
1158
  import { execSync as execSync8 } from "child_process";
1152
- import { appendFileSync as appendFileSync9, mkdtempSync as mkdtempSync8, unlinkSync as unlinkSync8, writeFileSync as writeFileSync9 } from "fs";
1159
+ import { appendFileSync as appendFileSync9, mkdtempSync as mkdtempSync8, rmSync as rmSync9, writeFileSync as writeFileSync9 } from "fs";
1153
1160
  import { tmpdir as tmpdir8 } from "os";
1154
1161
  import { join as join9 } from "path";
1155
1162
  var OpenCodeProvider = class {
@@ -1168,7 +1175,8 @@ var OpenCodeProvider = class {
1168
1175
  const promptFile = join9(tmpDir, "prompt.md");
1169
1176
  writeFileSync9(promptFile, prompt, "utf-8");
1170
1177
  try {
1171
- const command = `opencode run "$(cat '${promptFile}')"`;
1178
+ const modelFlag = opts.model ? `--model ${opts.model}` : "";
1179
+ const command = `opencode run ${modelFlag} "$(cat '${promptFile}')"`;
1172
1180
  const { proc, isPty } = spawnWithPty(command, {
1173
1181
  cwd: opts.cwd,
1174
1182
  env: { ...process.env, ...opts.env }
@@ -1222,7 +1230,7 @@ var OpenCodeProvider = class {
1222
1230
  };
1223
1231
  } finally {
1224
1232
  try {
1225
- unlinkSync8(promptFile);
1233
+ rmSync9(tmpDir, { recursive: true, force: true });
1226
1234
  } catch {
1227
1235
  }
1228
1236
  }
@@ -1267,8 +1275,8 @@ var ELIGIBLE_ERROR_PATTERNS = [
1267
1275
  /ECONNRESET/,
1268
1276
  /ENOTFOUND/,
1269
1277
  /fetch failed/i,
1270
- /timeout/i,
1271
- /timed?\s*out/i,
1278
+ /\btimeout\b/i,
1279
+ /\btimed?\s*out\b/i,
1272
1280
  /network.?error/i,
1273
1281
  /not installed/i,
1274
1282
  /not in PATH/i,
@@ -1534,9 +1542,12 @@ async function deleteProviderComments(prUrl) {
1534
1542
  const [, owner, repo, prNumber] = match;
1535
1543
  const { stdout } = await execa2("gh", [
1536
1544
  "api",
1545
+ "--paginate",
1546
+ "--jq",
1547
+ ".[]",
1537
1548
  `/repos/${owner}/${repo}/issues/${prNumber}/comments`
1538
1549
  ]);
1539
- const comments = JSON.parse(stdout);
1550
+ const comments = stdout.trim().split("\n").filter(Boolean).map((line) => JSON.parse(line));
1540
1551
  for (const comment of comments) {
1541
1552
  if (PROVIDER_ATTRIBUTION_RE.test(comment.body)) {
1542
1553
  try {
@@ -1572,7 +1583,7 @@ async function appendPrAttribution(prUrl, providerUsed) {
1572
1583
  // src/cli/detection.ts
1573
1584
  function getVersion() {
1574
1585
  try {
1575
- const pkgPath = resolvePath(new URL(".", import.meta.url).pathname, "../../package.json");
1586
+ const pkgPath = resolvePath(new URL(".", import.meta.url).pathname, "../package.json");
1576
1587
  const pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
1577
1588
  return pkg.version;
1578
1589
  } catch {
@@ -1581,7 +1592,7 @@ function getVersion() {
1581
1592
  }
1582
1593
  var CURSOR_FREE_PLAN_ERROR = "Free plans can only use Auto";
1583
1594
  async function isCursorFreePlan() {
1584
- const { mkdtempSync: mkdtempSync9, unlinkSync: unlinkSync12, writeFileSync: writeFileSync11 } = await import("fs");
1595
+ const { mkdtempSync: mkdtempSync9, unlinkSync: unlinkSync4, writeFileSync: writeFileSync11 } = await import("fs");
1585
1596
  const tmpDir = mkdtempSync9(join10(tmpdir9(), "lisa-cursor-check-"));
1586
1597
  const promptFile = join10(tmpDir, "prompt.txt");
1587
1598
  writeFileSync11(promptFile, "test", "utf-8");
@@ -1606,7 +1617,7 @@ async function isCursorFreePlan() {
1606
1617
  return errorOutput.includes(CURSOR_FREE_PLAN_ERROR);
1607
1618
  } finally {
1608
1619
  try {
1609
- unlinkSync12(promptFile);
1620
+ unlinkSync4(promptFile);
1610
1621
  } catch {
1611
1622
  }
1612
1623
  try {
@@ -1912,9 +1923,50 @@ async function runConfigWizard(existing) {
1912
1923
  if (clack2.isCancel(selected)) return process.exit(0);
1913
1924
  providerName = selected;
1914
1925
  }
1926
+ let gooseProvider;
1927
+ if (providerName === "goose") {
1928
+ const gooseProviderAnswer = await clack2.select({
1929
+ message: "Which backend should Goose use?",
1930
+ initialValue: initial?.provider_options?.goose?.goose_provider ?? process.env.GOOSE_PROVIDER ?? "gemini-cli",
1931
+ options: [
1932
+ { value: "gemini-cli", label: "Gemini CLI", hint: "requires Gemini CLI installed" },
1933
+ { value: "anthropic", label: "Anthropic", hint: "requires ANTHROPIC_API_KEY" },
1934
+ { value: "openai", label: "OpenAI", hint: "requires OPENAI_API_KEY" },
1935
+ { value: "google", label: "Google (direct)", hint: "requires GOOGLE_API_KEY" },
1936
+ { value: "ollama", label: "Ollama", hint: "local models" }
1937
+ ]
1938
+ });
1939
+ if (clack2.isCancel(gooseProviderAnswer)) return process.exit(0);
1940
+ gooseProvider = gooseProviderAnswer;
1941
+ } else if (providerName === "aider") {
1942
+ clack2.log.info(
1943
+ `Aider requires a direct LLM API key in your environment.
1944
+ Set one of: ${pc.bold("GEMINI_API_KEY")}, ${pc.bold("OPENAI_API_KEY")}, ${pc.bold("ANTHROPIC_API_KEY")}, etc.
1945
+ Aider does not use OAuth or cached credentials.`
1946
+ );
1947
+ } else if (providerName === "opencode") {
1948
+ clack2.log.info(
1949
+ `OpenCode tip: if you have MCP entries in ${pc.cyan("~/.config/opencode/config.json")},
1950
+ remove them or set the file to ${pc.cyan("{}")} \u2014 MCP tools can cause OpenCode to hang.`
1951
+ );
1952
+ }
1915
1953
  let selectedModels = [];
1916
1954
  let availableModels = providerModels[providerName];
1917
- if (providerName === "cursor") {
1955
+ if (providerName === "goose" && gooseProvider) {
1956
+ const gooseModelsByBackend = {
1957
+ "gemini-cli": [
1958
+ "gemini-2.5-pro",
1959
+ "gemini-2.5-flash",
1960
+ "gemini-2.0-flash",
1961
+ "gemini-2.5-flash-lite"
1962
+ ],
1963
+ anthropic: ["claude-sonnet-4-6", "claude-opus-4-6", "claude-haiku-4-5", "claude-sonnet-4-5"],
1964
+ openai: ["gpt-4o", "gpt-4o-mini", "o3", "o4-mini"],
1965
+ google: ["gemini-2.5-pro", "gemini-2.5-flash", "gemini-2.0-flash"],
1966
+ ollama: ["llama3.3", "qwen2.5-coder", "mistral"]
1967
+ };
1968
+ availableModels = gooseModelsByBackend[gooseProvider] ?? [];
1969
+ } else if (providerName === "cursor") {
1918
1970
  const isFree = await isCursorFreePlan();
1919
1971
  if (isFree) {
1920
1972
  availableModels = ["auto"];
@@ -2069,21 +2121,29 @@ Then reload: ${pc.cyan(`source ${shell}`)}`
2069
2121
  });
2070
2122
  if (clack2.isCancel(projectAnswer)) return process.exit(0);
2071
2123
  project = projectAnswer;
2124
+ const isLabelBasedSource = source === "github-issues" || source === "gitlab-issues";
2072
2125
  const pickFromAnswer = await clack2.text({
2073
- message: "Pick up issues in which status?",
2074
- initialValue: initial?.source_config.pick_from ?? "Backlog",
2075
- placeholder: "e.g. Backlog, Todo"
2126
+ message: isLabelBasedSource ? "Pick up issues in which state? (open, closed, or a label name)" : "Pick up issues in which status?",
2127
+ initialValue: initial?.source_config.pick_from ?? (isLabelBasedSource ? "open" : "Backlog"),
2128
+ placeholder: isLabelBasedSource ? "e.g. open" : "e.g. Backlog, Todo"
2076
2129
  });
2077
2130
  if (clack2.isCancel(pickFromAnswer)) return process.exit(0);
2078
2131
  pickFrom = pickFromAnswer;
2079
2132
  const inProgressAnswer = await clack2.text({
2080
- message: "Move to which status while the agent is working?",
2081
- initialValue: initial?.source_config.in_progress ?? "In Progress"
2133
+ message: isLabelBasedSource ? "Which label to apply while the agent is working? (must differ from pick_from label)" : "Move to which status while the agent is working?",
2134
+ initialValue: initial?.source_config.in_progress ?? "In Progress",
2135
+ placeholder: isLabelBasedSource ? "e.g. in-progress" : void 0
2082
2136
  });
2083
2137
  if (clack2.isCancel(inProgressAnswer)) return process.exit(0);
2084
2138
  inProgress = inProgressAnswer;
2139
+ if (isLabelBasedSource && inProgress === pickFrom) {
2140
+ clack2.log.warning(
2141
+ `"in_progress" label is the same as "pick_from" label ("${pickFrom}").
2142
+ This will cause Lisa to re-pick the issue on recovery. Consider using a different label.`
2143
+ );
2144
+ }
2085
2145
  const doneAnswer = await clack2.text({
2086
- message: "Move to which status after the PR is created?",
2146
+ message: isLabelBasedSource ? "Which label to apply after the PR is created?" : "Move to which status after the PR is created?",
2087
2147
  initialValue: initial?.source_config.done ?? "In Review"
2088
2148
  });
2089
2149
  if (clack2.isCancel(doneAnswer)) return process.exit(0);
@@ -2144,7 +2204,10 @@ Then reload: ${pc.cyan(`source ${shell}`)}`
2144
2204
  provider: providerName,
2145
2205
  provider_options: {
2146
2206
  ...initial?.provider_options || {},
2147
- [providerName]: { models: selectedModels }
2207
+ [providerName]: {
2208
+ models: selectedModels,
2209
+ ...gooseProvider ? { goose_provider: gooseProvider } : {}
2210
+ }
2148
2211
  },
2149
2212
  source,
2150
2213
  source_config: {
@@ -2217,8 +2280,8 @@ var feedback = defineCommand2({
2217
2280
  },
2218
2281
  async run({ args }) {
2219
2282
  const { fetchPrFeedback: fetchPrFeedback2, formatPrFeedbackEntry: formatPrFeedbackEntry2 } = await import("./pr-feedback-DGHNP3E7.js");
2220
- const { appendRawEntrySync } = await import("./guardrails-KI5NEJVE.js");
2221
- const { ensureCacheDir: ensureCacheDir2 } = await import("./paths-HQQDKACV.js");
2283
+ const { appendRawEntrySync } = await import("./guardrails-I5ACG5LQ.js");
2284
+ const { ensureCacheDir: ensureCacheDir2 } = await import("./paths-WQN4NBC6.js");
2222
2285
  const prUrl = args.pr;
2223
2286
  const issueId = args.issue ?? "unknown";
2224
2287
  const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
@@ -2781,14 +2844,14 @@ var LinearSource = class {
2781
2844
  `mutation($teamId: String!, $name: String!) {
2782
2845
  issueLabelCreate(input: { teamId: $teamId, name: $name }) {
2783
2846
  success
2784
- label { id name }
2847
+ issueLabel { id name }
2785
2848
  }
2786
2849
  }`,
2787
2850
  { teamId: issueData.issue.team.id, name: labelName }
2788
2851
  );
2789
- if (created.issueLabelCreate.success && created.issueLabelCreate.label) {
2852
+ if (created.issueLabelCreate.success && created.issueLabelCreate.issueLabel) {
2790
2853
  log(`Label "${labelName}" created automatically in team ${issueData.issue.team.id}`);
2791
- teamLabel = created.issueLabelCreate.label;
2854
+ teamLabel = created.issueLabelCreate.issueLabel;
2792
2855
  } else {
2793
2856
  const refetch = await gql(
2794
2857
  `query($identifier: String!) {
@@ -2989,7 +3052,7 @@ var PlaneSource = class {
2989
3052
  labelNames.map((name) => resolveLabelId(workspaceSlug, projectId, name))
2990
3053
  );
2991
3054
  const data = await planeGet(
2992
- `/workspaces/${workspaceSlug}/projects/${projectId}/issues/?state=${stateId}&per_page=100`
3055
+ `/workspaces/${workspaceSlug}/projects/${projectId}/work-items/?state=${stateId}&per_page=100`
2993
3056
  );
2994
3057
  const matching = data.results.filter((i) => i.state === stateId).filter((i) => labelIds.every((lid) => i.labels.includes(lid)));
2995
3058
  if (matching.length === 0) return null;
@@ -3002,14 +3065,14 @@ var PlaneSource = class {
3002
3065
  const blocked = [];
3003
3066
  for (const issue3 of matching) {
3004
3067
  const relations = await fetchAll(
3005
- `/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issue3.id}/relations/`
3068
+ `/workspaces/${workspaceSlug}/projects/${projectId}/work-items/${issue3.id}/relations/`
3006
3069
  );
3007
3070
  const blockerIds = relations.filter((r) => r.relation_type === "blocked_by").map((r) => r.related_issue);
3008
3071
  const activeBlockers = [];
3009
3072
  for (const blockerId of blockerIds) {
3010
3073
  try {
3011
3074
  const blocker = await planeGet(
3012
- `/workspaces/${workspaceSlug}/projects/${projectId}/issues/${blockerId}/`
3075
+ `/workspaces/${workspaceSlug}/projects/${projectId}/work-items/${blockerId}/`
3013
3076
  );
3014
3077
  if (!doneStateIds.has(blocker.state)) {
3015
3078
  activeBlockers.push(blockerId);
@@ -3050,7 +3113,7 @@ var PlaneSource = class {
3050
3113
  try {
3051
3114
  const { workspaceSlug, projectId, issueId } = parseIssueId(id);
3052
3115
  const issue2 = await planeGet(
3053
- `/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/`
3116
+ `/workspaces/${workspaceSlug}/projects/${projectId}/work-items/${issueId}/`
3054
3117
  );
3055
3118
  const webUrl = `${getAppUrl()}/${workspaceSlug}/projects/${projectId}/issues/${issue2.id}`;
3056
3119
  return {
@@ -3067,14 +3130,14 @@ var PlaneSource = class {
3067
3130
  const { workspaceSlug, projectId, issueId: planeIssueId } = parseIssueId(issueId);
3068
3131
  const stateId = await resolveStateId(workspaceSlug, projectId, stateName);
3069
3132
  await planePatch(
3070
- `/workspaces/${workspaceSlug}/projects/${projectId}/issues/${planeIssueId}/`,
3133
+ `/workspaces/${workspaceSlug}/projects/${projectId}/work-items/${planeIssueId}/`,
3071
3134
  { state: stateId }
3072
3135
  );
3073
3136
  }
3074
3137
  async attachPullRequest(issueId, prUrl) {
3075
3138
  const { workspaceSlug, projectId, issueId: planeIssueId } = parseIssueId(issueId);
3076
3139
  await planePost(
3077
- `/workspaces/${workspaceSlug}/projects/${projectId}/issues/${planeIssueId}/comments/`,
3140
+ `/workspaces/${workspaceSlug}/projects/${projectId}/work-items/${planeIssueId}/comments/`,
3078
3141
  { comment_html: `<p>Pull request: <a href="${prUrl}">${prUrl}</a></p>` }
3079
3142
  );
3080
3143
  }
@@ -3093,7 +3156,7 @@ var PlaneSource = class {
3093
3156
  labelNames.map((name) => resolveLabelId(workspaceSlug, projectId, name))
3094
3157
  );
3095
3158
  const data = await planeGet(
3096
- `/workspaces/${workspaceSlug}/projects/${projectId}/issues/?state=${stateId}&per_page=100`
3159
+ `/workspaces/${workspaceSlug}/projects/${projectId}/work-items/?state=${stateId}&per_page=100`
3097
3160
  );
3098
3161
  return data.results.filter((i) => i.state === stateId).filter((i) => labelIds.every((lid) => i.labels.includes(lid))).map((i) => {
3099
3162
  const webUrl = `${getAppUrl()}/${workspaceSlug}/projects/${projectId}/issues/${i.id}`;
@@ -3108,14 +3171,14 @@ var PlaneSource = class {
3108
3171
  async removeLabel(issueId, labelName) {
3109
3172
  const { workspaceSlug, projectId, issueId: planeIssueId } = parseIssueId(issueId);
3110
3173
  const issue2 = await planeGet(
3111
- `/workspaces/${workspaceSlug}/projects/${projectId}/issues/${planeIssueId}/`
3174
+ `/workspaces/${workspaceSlug}/projects/${projectId}/work-items/${planeIssueId}/`
3112
3175
  );
3113
3176
  const labels = await fetchLabels(workspaceSlug, projectId);
3114
3177
  const labelObj = labels.find((l) => l.name.toLowerCase() === labelName.toLowerCase());
3115
3178
  if (!labelObj || !issue2.labels.includes(labelObj.id)) return;
3116
3179
  const updatedLabels = issue2.labels.filter((lid) => lid !== labelObj.id);
3117
3180
  await planePatch(
3118
- `/workspaces/${workspaceSlug}/projects/${projectId}/issues/${planeIssueId}/`,
3181
+ `/workspaces/${workspaceSlug}/projects/${projectId}/work-items/${planeIssueId}/`,
3119
3182
  { labels: updatedLabels }
3120
3183
  );
3121
3184
  }
@@ -3157,6 +3220,24 @@ function extractStories(result) {
3157
3220
  if (Array.isArray(result)) return result;
3158
3221
  return result.data ?? [];
3159
3222
  }
3223
+ function extractNext(result) {
3224
+ if (Array.isArray(result)) return null;
3225
+ return result.next ?? null;
3226
+ }
3227
+ async function searchStoriesAll(body) {
3228
+ const all = [];
3229
+ let next = null;
3230
+ do {
3231
+ const req = next ? { ...body, next } : body;
3232
+ const result = await shortcutPost(
3233
+ "/api/v3/stories/search",
3234
+ req
3235
+ );
3236
+ all.push(...extractStories(result));
3237
+ next = extractNext(result);
3238
+ } while (next);
3239
+ return all;
3240
+ }
3160
3241
  async function resolveWorkflowStateId(stateName) {
3161
3242
  const workflows = await shortcutGet("/api/v3/workflows");
3162
3243
  for (const workflow of workflows) {
@@ -3218,15 +3299,11 @@ var ShortcutSource = class {
3218
3299
  const seen = /* @__PURE__ */ new Set();
3219
3300
  const allStories = [];
3220
3301
  for (const stateId of stateIds) {
3221
- const searchResult = await shortcutPost(
3222
- "/api/v3/stories/search",
3223
- {
3224
- workflow_state_id: stateId,
3225
- label_name: primaryLabel,
3226
- archived: false
3227
- }
3228
- );
3229
- for (const story2 of extractStories(searchResult)) {
3302
+ for (const story2 of await searchStoriesAll({
3303
+ workflow_state_id: stateId,
3304
+ label_name: primaryLabel,
3305
+ archived: false
3306
+ })) {
3230
3307
  if (!seen.has(story2.id)) {
3231
3308
  seen.add(story2.id);
3232
3309
  allStories.push(story2);
@@ -3322,15 +3399,11 @@ var ShortcutSource = class {
3322
3399
  const seen = /* @__PURE__ */ new Set();
3323
3400
  const allStories = [];
3324
3401
  for (const stateId of stateIds) {
3325
- const searchResult = await shortcutPost(
3326
- "/api/v3/stories/search",
3327
- {
3328
- workflow_state_id: stateId,
3329
- label_name: primaryLabel,
3330
- archived: false
3331
- }
3332
- );
3333
- for (const story of extractStories(searchResult)) {
3402
+ for (const story of await searchStoriesAll({
3403
+ workflow_state_id: stateId,
3404
+ label_name: primaryLabel,
3405
+ archived: false
3406
+ })) {
3334
3407
  if (!seen.has(story.id)) {
3335
3408
  seen.add(story.id);
3336
3409
  allStories.push(story);
@@ -3909,6 +3982,7 @@ async function injectRejectedPrFeedback(workspace, issueId, prUrls) {
3909
3982
  clearPrUrl(workspace, issueId);
3910
3983
  }
3911
3984
  async function recoverOrphanIssues(source, config2) {
3985
+ if (!config2.source_config.in_progress) return;
3912
3986
  if (config2.source_config.in_progress === config2.source_config.pick_from) return;
3913
3987
  const orphanConfig = {
3914
3988
  ...config2.source_config,
@@ -4609,6 +4683,7 @@ async function appendPrAttribution2(prUrl, providerUsed) {
4609
4683
  if (!getRes.ok) return;
4610
4684
  const prData = await getRes.json();
4611
4685
  const currentDescription = prData.description ?? "";
4686
+ const currentTitle = prData.title ?? "";
4612
4687
  const providerName = formatProviderName2(providerUsed);
4613
4688
  const attribution = `
4614
4689
 
@@ -4621,7 +4696,7 @@ async function appendPrAttribution2(prUrl, providerUsed) {
4621
4696
  Authorization: authHeader,
4622
4697
  "Content-Type": "application/json"
4623
4698
  },
4624
- body: JSON.stringify({ description: newDescription }),
4699
+ body: JSON.stringify({ description: newDescription, title: currentTitle }),
4625
4700
  signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS6)
4626
4701
  });
4627
4702
  } catch {
@@ -4722,7 +4797,7 @@ function buildPrCreateInstruction(platform2, targetBranch) {
4722
4797
  REPO=$(git remote get-url origin | sed 's/.*bitbucket\\.org[:/][^/]*\\///;s/\\.git$//')
4723
4798
  BRANCH=$(git branch --show-current)
4724
4799
  curl -X POST \\
4725
- -H "Authorization: Bearer $BITBUCKET_TOKEN" \\
4800
+ -H "Authorization: Basic $(printf '%s:%s' "$BITBUCKET_USERNAME" "$BITBUCKET_TOKEN" | base64)" \\
4726
4801
  -H "Content-Type: application/json" \\
4727
4802
  "https://api.bitbucket.org/2.0/repositories/$WORKSPACE/$REPO/pullrequests" \\
4728
4803
  --data "{\\"title\\":\\"<conventional-commit-title>\\",\\"description\\":\\"<markdown-summary>\\",\\"source\\":{\\"branch\\":{\\"name\\":\\"$BRANCH\\"}},\\"destination\\":{\\"branch\\":{\\"name\\":\\"${dest}\\"}}}"
@@ -4841,6 +4916,7 @@ function buildRulesSection(env, variant = "issue", extraRules = "") {
4841
4916
  - **ALL git commits, branch names, PR titles, and PR descriptions MUST be in English.**
4842
4917
  - The issue description may be in any language \u2014 read it for context but write all code artifacts in English.
4843
4918
  - Do NOT install new dependencies unless the issue explicitly requires it.
4919
+ - Do NOT use documentation lookup MCP tools (e.g., Context7, codesearch, Exa) \u2014 they have free-tier rate limits that will block your execution. Read files directly from the repository. Web search is allowed only when strictly necessary (e.g., looking up an external API format not available in the codebase).
4844
4920
  ${envRule}${extraRules}- If you get stuck or the issue is unclear, STOP and explain why.
4845
4921
  ${scopeRule}
4846
4922
  - If the repo has a CLAUDE.md, read it first and follow its conventions.`;
@@ -5172,14 +5248,17 @@ ${generatorBlock}
5172
5248
 
5173
5249
  2. **Determine execution order**: If multiple repos are affected, decide the order. Repos that produce APIs, schemas, or shared libraries should come first. Repos that consume them should come later.
5174
5250
 
5175
- 3. **Write the plan**: Create \`${resolvedPlanPath}\` with JSON:
5176
- \`\`\`json
5177
- {
5178
- "steps": [
5179
- { "repoPath": "<absolute path to repo>", "scope": "<what to implement in this repo>", "order": 1 },
5180
- { "repoPath": "<absolute path to repo>", "scope": "<what to implement in this repo>", "order": 2 }
5181
- ]
5182
- }
5251
+ 3. **Write the plan file to disk**: Use a bash command or file-write tool to write the plan to \`${resolvedPlanPath}\`.
5252
+ **You MUST write the file to disk. Do NOT print the JSON to stdout or in a code block.**
5253
+
5254
+ The file must be valid JSON with this structure (replace angle-bracket placeholders with real values):
5255
+ - \`repoPath\`: absolute path to the affected repository
5256
+ - \`scope\`: concise English description of what to implement in that repo
5257
+ - \`order\`: integer starting at 1 (lower = executes first)
5258
+
5259
+ Use your write_file tool, or a bash command such as:
5260
+ \`\`\`bash
5261
+ printf '%s' '{"steps":[{"repoPath":"/absolute/path","scope":"description of work","order":1}]}' > '${resolvedPlanPath}'
5183
5262
  \`\`\`
5184
5263
 
5185
5264
  ## Rules
@@ -5618,19 +5697,20 @@ function registerCleanup() {
5618
5697
  }
5619
5698
 
5620
5699
  // src/loop/manifest.ts
5621
- import { existsSync as existsSync8, readFileSync as readFileSync8, unlinkSync as unlinkSync9 } from "fs";
5700
+ import { existsSync as existsSync8, readFileSync as readFileSync8, unlinkSync } from "fs";
5622
5701
  function readLisaManifest(cwd, issueId) {
5623
5702
  const manifestPath = getManifestPath(cwd, issueId);
5624
5703
  if (!existsSync8(manifestPath)) return null;
5625
5704
  try {
5626
5705
  return JSON.parse(readFileSync8(manifestPath, "utf-8").trim());
5627
5706
  } catch {
5707
+ warn(`Failed to parse manifest at ${manifestPath} \u2014 agent may not have written it correctly`);
5628
5708
  return null;
5629
5709
  }
5630
5710
  }
5631
5711
  function cleanupManifest(cwd, issueId) {
5632
5712
  try {
5633
- unlinkSync9(getManifestPath(cwd, issueId));
5713
+ unlinkSync(getManifestPath(cwd, issueId));
5634
5714
  } catch {
5635
5715
  }
5636
5716
  }
@@ -5664,14 +5744,13 @@ function readPlanFile(filePath) {
5664
5744
  }
5665
5745
 
5666
5746
  // src/loop/multi-repo-session.ts
5667
- import { appendFileSync as appendFileSync10, unlinkSync as unlinkSync10 } from "fs";
5747
+ import { appendFileSync as appendFileSync10, unlinkSync as unlinkSync2 } from "fs";
5668
5748
  import { join as join14, resolve as resolve7 } from "path";
5669
5749
  async function runWorktreeMultiRepoSession(config2, issue2, logFile, session, models) {
5670
5750
  const workspace = resolve7(config2.workspace);
5671
- const safeId = issue2.id.replace(/[^a-zA-Z0-9_-]/g, "_");
5672
- const planPath = join14(workspace, `.lisa-plan-${safeId}.json`);
5751
+ const planPath = getPlanPath(workspace, issue2.id);
5673
5752
  try {
5674
- unlinkSync10(planPath);
5753
+ unlinkSync2(planPath);
5675
5754
  } catch {
5676
5755
  }
5677
5756
  initLogFile(logFile);
@@ -5710,7 +5789,7 @@ ${planResult.output}
5710
5789
  if (!planResult.success) {
5711
5790
  error(`Planning phase failed for ${issue2.id}. Check ${logFile}`);
5712
5791
  try {
5713
- unlinkSync10(planPath);
5792
+ unlinkSync2(planPath);
5714
5793
  } catch {
5715
5794
  }
5716
5795
  activeProviderPids.delete(issue2.id);
@@ -5725,7 +5804,7 @@ ${planResult.output}
5725
5804
  if (!plan?.steps || plan.steps.length === 0) {
5726
5805
  error(`Agent did not produce a valid execution plan for ${issue2.id}. Aborting.`);
5727
5806
  try {
5728
- unlinkSync10(planPath);
5807
+ unlinkSync2(planPath);
5729
5808
  } catch {
5730
5809
  }
5731
5810
  activeProviderPids.delete(issue2.id);
@@ -5741,7 +5820,7 @@ ${planResult.output}
5741
5820
  `Plan produced ${sortedSteps.length} step(s): ${sortedSteps.map((s) => s.repoPath).join(" \u2192 ")}`
5742
5821
  );
5743
5822
  try {
5744
- unlinkSync10(planPath);
5823
+ unlinkSync2(planPath);
5745
5824
  } catch {
5746
5825
  }
5747
5826
  const prUrls = [];
@@ -6470,13 +6549,13 @@ async function getChangedFiles(repoPath, baseBranch, dependencyBranch) {
6470
6549
  }
6471
6550
 
6472
6551
  // src/loop/branch-session.ts
6473
- import { appendFileSync as appendFileSync12, unlinkSync as unlinkSync11 } from "fs";
6552
+ import { appendFileSync as appendFileSync12, unlinkSync as unlinkSync3 } from "fs";
6474
6553
  import { join as join16, resolve as resolve10 } from "path";
6475
6554
  async function runBranchSession(config2, issue2, logFile, session, models) {
6476
6555
  const workspace = resolve10(config2.workspace);
6477
6556
  const manifestPath = join16(workspace, ".lisa-manifest.json");
6478
6557
  try {
6479
- unlinkSync11(manifestPath);
6558
+ unlinkSync3(manifestPath);
6480
6559
  } catch {
6481
6560
  }
6482
6561
  const testRunner = detectTestRunner(workspace);
@@ -6579,7 +6658,7 @@ ${result.output}
6579
6658
  }
6580
6659
  const manifest = readManifestFile(manifestPath);
6581
6660
  try {
6582
- unlinkSync11(manifestPath);
6661
+ unlinkSync3(manifestPath);
6583
6662
  } catch {
6584
6663
  }
6585
6664
  let prUrl = manifest?.prUrl;
@@ -7036,7 +7115,7 @@ var run = defineCommand5({
7036
7115
  if (isTTY) {
7037
7116
  const { render } = await import("ink");
7038
7117
  const { createElement } = await import("react");
7039
- const { KanbanApp } = await import("./kanban-ECJSRP4C.js");
7118
+ const { KanbanApp } = await import("./kanban-QZ5NRPJ5.js");
7040
7119
  const demoConfig = {
7041
7120
  provider: "claude",
7042
7121
  source: "linear",
@@ -7073,6 +7152,12 @@ var run = defineCommand5({
7073
7152
  label: args.label,
7074
7153
  bell: args.bell
7075
7154
  });
7155
+ if (merged.provider === "goose") {
7156
+ const gooseProvider = merged.provider_options?.goose?.goose_provider;
7157
+ if (gooseProvider && !process.env.GOOSE_PROVIDER) {
7158
+ process.env.GOOSE_PROVIDER = gooseProvider;
7159
+ }
7160
+ }
7076
7161
  if (args.lifecycle || args["lifecycle-timeout"]) {
7077
7162
  const lifecycleTimeout = args["lifecycle-timeout"] ? Number.parseInt(args["lifecycle-timeout"], 10) : void 0;
7078
7163
  merged.lifecycle = {
@@ -7105,7 +7190,7 @@ Add them to your ${shell} and run: source ${shell}`));
7105
7190
  if (isTTY) {
7106
7191
  const { render } = await import("ink");
7107
7192
  const { createElement } = await import("react");
7108
- const { KanbanApp } = await import("./kanban-ECJSRP4C.js");
7193
+ const { KanbanApp } = await import("./kanban-QZ5NRPJ5.js");
7109
7194
  render(createElement(KanbanApp, { config: merged }), { exitOnCtrlC: false });
7110
7195
  }
7111
7196
  await runLoop(merged, {
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  kanbanEmitter,
4
4
  useKanbanState
5
- } from "./chunk-WZIPTRJL.js";
5
+ } from "./chunk-ITQEGO5A.js";
6
6
  import {
7
7
  resetTitle,
8
8
  startSpinner,
@@ -9,7 +9,7 @@ import {
9
9
  getPrCachePath,
10
10
  projectHash,
11
11
  rotateLogFiles
12
- } from "./chunk-OYQ6TOAG.js";
12
+ } from "./chunk-GZ2ZAQO4.js";
13
13
  export {
14
14
  ensureCacheDir,
15
15
  getCacheDir,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tarcisiopgs/lisa",
3
- "version": "1.15.0",
3
+ "version": "1.16.0",
4
4
  "description": "Autonomous issue resolver",
5
5
  "keywords": [
6
6
  "loop",
@@ -27,7 +27,7 @@
27
27
  "lisa": "dist/index.js"
28
28
  },
29
29
  "dependencies": {
30
- "@clack/prompts": "^1.0.1",
30
+ "@clack/prompts": "^1.1.0",
31
31
  "citty": "^0.2.1",
32
32
  "execa": "^9.6.1",
33
33
  "ink": "^6.8.0",
@@ -43,7 +43,7 @@
43
43
  "@vitest/coverage-v8": "^4.0.18",
44
44
  "concurrently": "^9.2.1",
45
45
  "husky": "^9.1.7",
46
- "lint-staged": "^16.3.1",
46
+ "lint-staged": "^16.3.2",
47
47
  "tsup": "^8.5.1",
48
48
  "tsx": "^4.21.0",
49
49
  "typescript": "^5.9.3",