@tarcisiopgs/lisa 1.15.0 → 1.17.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 +38 -3
- package/dist/{chunk-OYQ6TOAG.js → chunk-GZ2ZAQO4.js} +9 -2
- package/dist/{chunk-NXGXGHS3.js → chunk-UQPR5OXK.js} +1 -1
- package/dist/{chunk-WZIPTRJL.js → chunk-WDGLMZB7.js} +9 -4
- package/dist/{guardrails-KI5NEJVE.js → guardrails-I5ACG5LQ.js} +2 -2
- package/dist/index.js +353 -114
- package/dist/{kanban-ECJSRP4C.js → kanban-LG26AUFK.js} +5 -1
- package/dist/{paths-HQQDKACV.js → paths-WQN4NBC6.js} +1 -1
- package/package.json +3 -3
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
|
---
|
|
@@ -184,6 +189,7 @@ repos:
|
|
|
184
189
|
loop:
|
|
185
190
|
cooldown: 10 # seconds between issues
|
|
186
191
|
max_sessions: 0 # 0 = unlimited
|
|
192
|
+
session_timeout: 0 # seconds per provider run (0 = disabled)
|
|
187
193
|
|
|
188
194
|
# Optional — kill stuck providers
|
|
189
195
|
overseer:
|
|
@@ -196,6 +202,22 @@ validation:
|
|
|
196
202
|
require_acceptance_criteria: true
|
|
197
203
|
```
|
|
198
204
|
|
|
205
|
+
### Source-specific notes
|
|
206
|
+
|
|
207
|
+
**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.
|
|
208
|
+
|
|
209
|
+
**Trello** — `team`, `pick_from`, `in_progress`, and `done` are list **names** (not IDs).
|
|
210
|
+
|
|
211
|
+
**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.
|
|
212
|
+
|
|
213
|
+
**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.
|
|
214
|
+
|
|
215
|
+
**Aider** — requires a direct LLM API key (`GEMINI_API_KEY`, `OPENAI_API_KEY`, or `ANTHROPIC_API_KEY`). Does not support OAuth or cached credentials.
|
|
216
|
+
|
|
217
|
+
**OpenCode** — if `~/.config/opencode/config.json` contains MCP entries, remove them or set the file to `{}` to prevent OpenCode from hanging on startup.
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
199
221
|
### Workflow Modes
|
|
200
222
|
|
|
201
223
|
**Branch** — The agent creates a branch in your current checkout. Simple setup, works everywhere.
|
|
@@ -206,6 +228,19 @@ When `--concurrency` is greater than 1, worktree mode is enforced automatically.
|
|
|
206
228
|
|
|
207
229
|
---
|
|
208
230
|
|
|
231
|
+
### Session Timeout
|
|
232
|
+
|
|
233
|
+
If a provider hangs (e.g. misconfigured model, network issue), Lisa can kill it after a configurable duration:
|
|
234
|
+
|
|
235
|
+
```yaml
|
|
236
|
+
loop:
|
|
237
|
+
session_timeout: 300 # kill provider after 5 minutes (0 = disabled, default)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
When the timeout fires, the provider process is killed and the error is eligible for fallback — Lisa will try the next model in your chain. This is disabled by default so long-running sessions work uninterrupted.
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
209
244
|
## Writing Issues
|
|
210
245
|
|
|
211
246
|
Issue quality is the single biggest factor in PR quality. Lisa validates issues before accepting them — vague tickets without clear criteria are skipped and labelled `needs-spec`.
|
|
@@ -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
|
-
|
|
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.
|
|
451
|
+
return link.state !== "closed";
|
|
452
452
|
}
|
|
453
453
|
return false;
|
|
454
|
-
}).map((link) => link.
|
|
454
|
+
}).map((link) => link.iid);
|
|
455
455
|
if (activeBlockers.length === 0) {
|
|
456
456
|
unblocked.push(issue2);
|
|
457
457
|
} else {
|
|
@@ -743,6 +743,9 @@ function useKanbanState(bellEnabled) {
|
|
|
743
743
|
})
|
|
744
744
|
);
|
|
745
745
|
};
|
|
746
|
+
const onLogFile = (issueId, logFile) => {
|
|
747
|
+
setCards((prev) => prev.map((c) => c.id === issueId ? { ...c, logFile } : c));
|
|
748
|
+
};
|
|
746
749
|
const onOutput = (issueId, text) => {
|
|
747
750
|
setCards(
|
|
748
751
|
(prev) => prev.map((c) => c.id === issueId ? { ...c, outputLog: c.outputLog + text } : c)
|
|
@@ -757,6 +760,7 @@ function useKanbanState(bellEnabled) {
|
|
|
757
760
|
kanbanEmitter.on("issue:killed", onKilled);
|
|
758
761
|
kanbanEmitter.on("provider:paused", onProviderPaused);
|
|
759
762
|
kanbanEmitter.on("provider:resumed", onProviderResumed);
|
|
763
|
+
kanbanEmitter.on("issue:log-file", onLogFile);
|
|
760
764
|
kanbanEmitter.on("issue:output", onOutput);
|
|
761
765
|
const onModelChanged = (model) => setModelInUse(model);
|
|
762
766
|
kanbanEmitter.on("provider:model-changed", onModelChanged);
|
|
@@ -786,6 +790,7 @@ function useKanbanState(bellEnabled) {
|
|
|
786
790
|
kanbanEmitter.off("issue:killed", onKilled);
|
|
787
791
|
kanbanEmitter.off("provider:paused", onProviderPaused);
|
|
788
792
|
kanbanEmitter.off("provider:resumed", onProviderResumed);
|
|
793
|
+
kanbanEmitter.off("issue:log-file", onLogFile);
|
|
789
794
|
kanbanEmitter.off("issue:output", onOutput);
|
|
790
795
|
kanbanEmitter.off("provider:model-changed", onModelChanged);
|
|
791
796
|
kanbanEmitter.off("work:empty", onEmpty);
|