@tarcisiopgs/lisa 1.26.1 → 1.27.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
@@ -56,13 +56,27 @@ If something fails — pre-push hooks, quota limits, stuck processes — Lisa ha
56
56
  | GitHub Copilot CLI | `copilot` | Aider | `aider` |
57
57
  | OpenCode | `opencode` | OpenAI Codex | `codex` |
58
58
 
59
- Configure a fallback chain:
59
+ Configure models and provider-specific options:
60
60
 
61
61
  ```yaml
62
62
  provider: claude
63
- models:
64
- - claude-sonnet-4-6 # primary
65
- - claude-opus-4-6 # fallback
63
+ provider_options:
64
+ claude:
65
+ models:
66
+ - claude-sonnet-4-6 # primary
67
+ - claude-opus-4-6 # fallback
68
+ effort: high # optional: low, medium, high, max
69
+ ```
70
+
71
+ Goose requires a backend selection:
72
+
73
+ ```yaml
74
+ provider: goose
75
+ provider_options:
76
+ goose:
77
+ goose_provider: gemini-cli # gemini-cli, anthropic, openai, google, ollama
78
+ models:
79
+ - gemini-2.5-pro
66
80
  ```
67
81
 
68
82
  ## Commands
@@ -77,10 +91,13 @@ lisa run --issue INT-42 # process a specific issue
77
91
  lisa run --limit 5 # stop after 5 issues
78
92
  lisa init # create .lisa/config.yaml interactively
79
93
  lisa status # show session stats
94
+ lisa doctor # diagnose setup issues (config, provider, env, git)
80
95
  lisa context refresh # regenerate project context
81
96
  lisa feedback --pr URL # inject PR review feedback into guardrails
82
97
  ```
83
98
 
99
+ Append `--json` to any command for machine-readable output. Use `--verbose` / `--quiet` to control log verbosity.
100
+
84
101
  ## Configuration
85
102
 
86
103
  Config lives in `.lisa/config.yaml`. Run `lisa init` to create it interactively.
@@ -93,11 +110,14 @@ workflow: worktree # "worktree" (isolated) or "branch" (in-place)
93
110
  source_config:
94
111
  scope: Engineering
95
112
  project: Web App
96
- label: ready
113
+ label: ready # or array: [ready, urgent]
114
+ remove_label: ready # label to remove on completion (defaults to label)
97
115
  pick_from: Backlog
98
116
  in_progress: In Progress
99
117
  done: In Review
100
118
 
119
+ bell: true # terminal bell on issue completion
120
+
101
121
  platform: cli # "cli" (gh), "token" (GITHUB_TOKEN), "gitlab", "bitbucket"
102
122
  base_branch: main
103
123
  ```
@@ -120,6 +140,21 @@ SHORTCUT_API_TOKEN=""
120
140
  GITLAB_TOKEN=""
121
141
  GITHUB_TOKEN=""
122
142
  JIRA_BASE_URL="" && JIRA_EMAIL="" && JIRA_API_TOKEN=""
143
+
144
+ # Self-hosted instances (optional)
145
+ PLANE_BASE_URL="" # default: https://api.plane.so
146
+ GITLAB_BASE_URL="" # default: https://gitlab.com
147
+ PLANE_WORKSPACE="" # fallback for source_config.scope
148
+
149
+ # Goose backend (required when provider: goose)
150
+ GOOSE_PROVIDER="" # gemini-cli, anthropic, openai, google, ollama
151
+ GOOSE_MODEL="" # model name for the selected backend
152
+
153
+ # AI provider API keys (used by Aider / Goose / wizard auto-detection)
154
+ ANTHROPIC_API_KEY=""
155
+ OPENAI_API_KEY=""
156
+ GEMINI_API_KEY=""
157
+ GOOGLE_API_KEY="" # for Goose with goose_provider: google
123
158
  ```
124
159
 
125
160
  </details>
@@ -133,6 +168,7 @@ JIRA_BASE_URL="" && JIRA_EMAIL="" && JIRA_API_TOKEN=""
133
168
  | `project` | Project name | — | Project ID | — | — | — | — |
134
169
  | `pick_from` | Status name | List name | State name | Workflow state | — | — | Status name |
135
170
  | `label` | Label | Label | Label | Label | Label | Label | Label |
171
+ | `remove_label` | Label | Label | Label | Label | — | — | — |
136
172
  | `in_progress` | Status | Column | State | Workflow state | Label | Label | Status |
137
173
  | `done` | Status | Column | State | Workflow state | Closes issue | Closes issue | Status |
138
174
 
@@ -163,6 +199,7 @@ Lisa runs a planning phase, then executes steps sequentially — one worktree an
163
199
  loop:
164
200
  cooldown: 10 # seconds between issues
165
201
  session_timeout: 0 # max seconds per provider run (0 = disabled)
202
+ output_stall_timeout: 120 # seconds without stdout before killing provider (0 = disabled)
166
203
 
167
204
  overseer:
168
205
  enabled: true
@@ -201,15 +238,24 @@ Acceptance criteria:
201
238
 
202
239
  ## TUI
203
240
 
204
- The real-time Kanban board shows issue progress, streams provider output, and detects PR merges.
241
+ The real-time Kanban board shows issue progress, streams provider output, and detects PR merges. The sidebar legend updates contextually — only the shortcuts active in the current view are shown.
242
+
243
+ **Board view**
205
244
 
206
245
  | Key | Action | Key | Action |
207
246
  |-----|--------|-----|--------|
208
247
  | `←` `→` | Switch columns | `p` | Pause / resume provider |
209
- | `↑` `↓` | Navigate cards | `k` | Kill current issue |
210
- | `↵` | Open detail view | `s` | Skip current issue |
211
- | `Esc` | Back to board | `o` | Open PR in browser |
212
- | `q` | Quit | | |
248
+ | `1` `2` `3` | Jump to column | `k` | Kill current issue |
249
+ | `↑` `↓` | Navigate cards | `s` | Skip current issue |
250
+ | `↵` | Open detail view | `q` | Quit |
251
+
252
+ **Detail view**
253
+
254
+ | Key | Action |
255
+ |-----|--------|
256
+ | `↑` `↓` | Scroll output log |
257
+ | `o` | Open PR in browser |
258
+ | `Esc` | Back to board |
213
259
 
214
260
  ## License
215
261
 
@@ -81,7 +81,7 @@ ${newEntryText}`;
81
81
 
82
82
  ${rotated.join("\n\n")}`;
83
83
  }
84
- writeFileSync(path, content, "utf-8");
84
+ writeFileSync(path, content, { encoding: "utf-8", mode: 384 });
85
85
  }
86
86
  function appendRawEntry(dir, entryText) {
87
87
  writeLock = writeLock.then(() => appendRawEntrySync(dir, entryText)).catch(() => {
@@ -108,7 +108,7 @@ ${entryText}`;
108
108
 
109
109
  ${rotated.join("\n\n")}`;
110
110
  }
111
- writeFileSync(path, content, "utf-8");
111
+ writeFileSync(path, content, { encoding: "utf-8", mode: 384 });
112
112
  }
113
113
  function formatEntry(entry) {
114
114
  return [
@@ -2,11 +2,16 @@
2
2
 
3
3
  // src/cli/detection.ts
4
4
  import { execSync } from "child_process";
5
- import { existsSync, readdirSync, readFileSync } from "fs";
5
+ import { existsSync, readdirSync, readFileSync, rmSync } from "fs";
6
6
  import { tmpdir } from "os";
7
7
  import { join, resolve as resolvePath } from "path";
8
8
  import * as clack from "@clack/prompts";
9
9
 
10
+ // src/errors.ts
11
+ function formatError(err) {
12
+ return err instanceof Error ? err.message : String(err);
13
+ }
14
+
10
15
  // src/git/github.ts
11
16
  import { execa } from "execa";
12
17
 
@@ -99,6 +104,15 @@ async function appendPrAttribution(prUrl, providerUsed) {
99
104
  } catch {
100
105
  }
101
106
  }
107
+ async function appendPrBody(prUrl, content) {
108
+ try {
109
+ const { stdout: bodyJson } = await execa("gh", ["pr", "view", prUrl, "--json", "body"]);
110
+ const { body } = JSON.parse(bodyJson);
111
+ const newBody = (body ?? "") + content;
112
+ await execa("gh", ["pr", "edit", prUrl, "--body", newBody]);
113
+ } catch {
114
+ }
115
+ }
102
116
 
103
117
  // src/cli/detection.ts
104
118
  function getVersion() {
@@ -112,7 +126,7 @@ function getVersion() {
112
126
  }
113
127
  var CURSOR_FREE_PLAN_ERROR = "Free plans can only use Auto";
114
128
  async function isCursorFreePlan() {
115
- const { mkdtempSync, unlinkSync, writeFileSync } = await import("fs");
129
+ const { mkdtempSync, writeFileSync } = await import("fs");
116
130
  const tmpDir = mkdtempSync(join(tmpdir(), "lisa-cursor-check-"));
117
131
  const promptFile = join(tmpDir, "prompt.txt");
118
132
  writeFileSync(promptFile, "test", "utf-8");
@@ -133,15 +147,11 @@ async function isCursorFreePlan() {
133
147
  });
134
148
  return output.includes(CURSOR_FREE_PLAN_ERROR);
135
149
  } catch (err) {
136
- const errorOutput = err instanceof Error ? err.message : String(err);
150
+ const errorOutput = formatError(err);
137
151
  return errorOutput.includes(CURSOR_FREE_PLAN_ERROR);
138
152
  } finally {
139
153
  try {
140
- unlinkSync(promptFile);
141
- } catch {
142
- }
143
- try {
144
- execSync(`rm -rf ${tmpDir}`, { stdio: "ignore" });
154
+ rmSync(tmpDir, { recursive: true, force: true });
145
155
  } catch {
146
156
  }
147
157
  }
@@ -346,6 +356,8 @@ export {
346
356
  stripProviderAttribution,
347
357
  isGhCliAvailable,
348
358
  appendPrAttribution,
359
+ appendPrBody,
360
+ formatError,
349
361
  getVersion,
350
362
  isCursorFreePlan,
351
363
  fetchCursorModels,