@tarcisiopgs/lisa 1.33.3 → 1.34.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 +37 -5
- package/dist/{chunk-5724FKM6.js → chunk-2DONWCCQ.js} +94 -14
- package/dist/{chunk-2EQI6U5O.js → chunk-5FODVMWF.js} +409 -25
- package/dist/{chunk-UDQRHMVH.js → chunk-S2PRXET6.js} +20 -4
- package/dist/{chunk-PPRXJHPW.js → chunk-V44FTYWZ.js} +7 -1
- package/dist/index.js +83 -36
- package/dist/{kanban-MKRXRMTL.js → kanban-CRHTDRBU.js} +13 -3
- package/dist/{loop-ZPYCRA6I.js → loop-D4AKZUXG.js} +3 -3
- package/dist/{tui-bridge-ZLL4U7W3.js → tui-bridge-6C4IRKUQ.js} +4 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -28,7 +28,7 @@ lisa # start the agent loop
|
|
|
28
28
|
## How It Works
|
|
29
29
|
|
|
30
30
|
```
|
|
31
|
-
Plan → Create issues → Fetch → Implement → Push → Open PR → Update board → Next
|
|
31
|
+
Plan → Create issues → Fetch → Implement → Push → Open PR → CI Monitor → Review Monitor → Update board → Next
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
Lisa starts and shows a Kanban board. If the queue is empty, press `n` to plan — describe a goal and the AI brainstorms with you (asking clarifying questions), presents its understanding for your confirmation, then decomposes the goal into atomic issues created directly in your tracker. You can review, edit, reorder, delete, or regenerate the plan with feedback before approving. Press `r` to start processing. Lisa picks the highest-priority labeled issue, moves it to "In Progress", sends a structured prompt to the AI agent, and monitors execution. The agent works in an isolated git worktree, implements the change, runs tests, and commits. Lisa pushes, opens a PR, moves the ticket to "In Review", and picks up the next one.
|
|
@@ -47,11 +47,16 @@ If something fails — pre-push hooks, quota limits, stuck processes — Lisa ha
|
|
|
47
47
|
- **Model fallback** — chain models; transient errors (429, quota, timeout) auto-switch to the next
|
|
48
48
|
- **Real-time TUI** — Kanban board with live provider output, plan mode, merge PRs with `m`
|
|
49
49
|
- **CI monitoring** — polls CI after PR creation, re-invokes the agent to fix failures automatically
|
|
50
|
+
- **Review monitoring** — polls PR reviews after CI, auto-addresses reviewer feedback (GitHub)
|
|
51
|
+
- **Reaction engine** — configurable actions for CI failures, review changes, stuck agents
|
|
52
|
+
- **Session state tracking** — real-time visibility into agent pipeline phase (implementing → validating → CI → review)
|
|
53
|
+
- **Smart activity detection** — reads agent session logs to prevent false stuck kills during analysis phases
|
|
50
54
|
- **Progress comments** — posts real-time status updates on issues as Lisa works through stages
|
|
51
55
|
- **Context enrichment** — greps for issue-related files and surfaces them in the agent prompt
|
|
52
56
|
- **PR reviewers & assignees** — auto-request reviews and assign PRs via config; `self` keyword resolves to the authenticated user
|
|
53
57
|
- **Self-healing** — orphan recovery on startup, push failure retry, stuck process detection
|
|
54
58
|
- **Guardrails** — past failures are injected into future prompts to avoid repeating mistakes
|
|
59
|
+
- **Lineage context** — plan-decomposed issues get sibling task awareness, preventing duplicate work in concurrent mode
|
|
55
60
|
- **Project context** — auto-generates `.lisa/context.md` with your stack, conventions, and constraints
|
|
56
61
|
|
|
57
62
|
## Providers
|
|
@@ -109,6 +114,7 @@ lisa config --set loop.cooldown=5 # set nested config values
|
|
|
109
114
|
lisa doctor # diagnose setup issues (config, provider, env, git)
|
|
110
115
|
lisa context refresh # regenerate project context
|
|
111
116
|
lisa feedback --pr URL # inject PR review feedback into guardrails
|
|
117
|
+
lisa sessions # list active session states (supports --json)
|
|
112
118
|
```
|
|
113
119
|
|
|
114
120
|
Append `--json` to any command for machine-readable output. Use `--verbose` / `--quiet` to control log verbosity.
|
|
@@ -252,6 +258,31 @@ ci_monitor:
|
|
|
252
258
|
poll_timeout: 600 # max seconds to wait for CI
|
|
253
259
|
block_on_failure: false # revert issue if CI never passes
|
|
254
260
|
|
|
261
|
+
# Post-PR review monitoring (GitHub only)
|
|
262
|
+
review_monitor:
|
|
263
|
+
enabled: true
|
|
264
|
+
max_retries: 2 # fix attempts on review changes (default: 2)
|
|
265
|
+
poll_interval: 60 # seconds between review checks (default: 60)
|
|
266
|
+
poll_timeout: 3600 # max seconds to wait for review (default: 3600)
|
|
267
|
+
|
|
268
|
+
# Configurable reactions (override defaults)
|
|
269
|
+
reactions:
|
|
270
|
+
ci_failed:
|
|
271
|
+
action: reinvoke # reinvoke | notify | skip
|
|
272
|
+
max_retries: 3
|
|
273
|
+
escalate_after: 30m
|
|
274
|
+
changes_requested:
|
|
275
|
+
action: reinvoke
|
|
276
|
+
max_retries: 2
|
|
277
|
+
escalate_after: 1h
|
|
278
|
+
approved:
|
|
279
|
+
action: notify
|
|
280
|
+
agent_stuck:
|
|
281
|
+
action: notify
|
|
282
|
+
validation_failed:
|
|
283
|
+
action: reinvoke
|
|
284
|
+
max_retries: 2
|
|
285
|
+
|
|
255
286
|
progress_comments:
|
|
256
287
|
enabled: true # post real-time status on issues
|
|
257
288
|
|
|
@@ -275,7 +306,7 @@ hooks:
|
|
|
275
306
|
After the agent implements an issue, Lisa runs a multi-stage validation pipeline before creating a PR:
|
|
276
307
|
|
|
277
308
|
```
|
|
278
|
-
Agent implements → Proof of Work (lint/test/typecheck) → Spec Compliance → PR
|
|
309
|
+
Agent implements → Proof of Work (lint/test/typecheck) → Spec Compliance → PR → CI Monitor → Review Monitor
|
|
279
310
|
```
|
|
280
311
|
|
|
281
312
|
**Proof of Work** runs configured shell commands (lint, typecheck, test). If any fail, the agent is re-invoked with the error output to fix the issue.
|
|
@@ -318,9 +349,10 @@ The real-time Kanban board shows issue progress, streams provider output, and de
|
|
|
318
349
|
| Key | Action | Key | Action |
|
|
319
350
|
|-----|--------|-----|--------|
|
|
320
351
|
| `←` `→` | Switch columns | `k` | Kill current issue |
|
|
321
|
-
| `↑` `↓` | Navigate cards | `
|
|
322
|
-
| `↵` | Open detail view | `
|
|
323
|
-
| `p` | Pause / resume | `
|
|
352
|
+
| `↑` `↓` | Navigate cards | `s` | Skip current issue |
|
|
353
|
+
| `↵` | Open detail view | `n` | Open plan mode |
|
|
354
|
+
| `p` | Pause / resume | `r` | Run (from idle) |
|
|
355
|
+
| `m` | Merge PR (opens detail + triggers merge) | `q` | Quit |
|
|
324
356
|
|
|
325
357
|
**Detail view**
|
|
326
358
|
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
normalizeLabels,
|
|
12
12
|
ok,
|
|
13
13
|
warn
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-V44FTYWZ.js";
|
|
15
15
|
import {
|
|
16
16
|
appendEntry,
|
|
17
17
|
buildGuardrailsSection,
|
|
@@ -1180,7 +1180,8 @@ function buildPrompt(opts) {
|
|
|
1180
1180
|
step,
|
|
1181
1181
|
previousResults = [],
|
|
1182
1182
|
isLastStep = false,
|
|
1183
|
-
relevantFiles
|
|
1183
|
+
relevantFiles,
|
|
1184
|
+
lineageBlock
|
|
1184
1185
|
} = opts;
|
|
1185
1186
|
let manifestPath = opts.manifestPath;
|
|
1186
1187
|
if (!manifestPath && variant === "branch" && config) {
|
|
@@ -1384,6 +1385,7 @@ ${branchRenameInstruction}
|
|
|
1384
1385
|
rulesSection = buildRulesSection(projectContext?.environment);
|
|
1385
1386
|
}
|
|
1386
1387
|
const taskHint = buildTaskTypeHint(issue.title);
|
|
1388
|
+
const lineageSection = lineageBlock ?? "";
|
|
1387
1389
|
return `${preamble}${taskHint}
|
|
1388
1390
|
${workContext}${contextBlock ? `
|
|
1389
1391
|
${contextBlock}
|
|
@@ -1391,6 +1393,8 @@ ${contextBlock}
|
|
|
1391
1393
|
${relevantFilesBlock}
|
|
1392
1394
|
` : ""}${depBlock ? `
|
|
1393
1395
|
${depBlock}
|
|
1396
|
+
` : ""}${lineageSection ? `
|
|
1397
|
+
${lineageSection}
|
|
1394
1398
|
` : ""}
|
|
1395
1399
|
## Issue
|
|
1396
1400
|
|
|
@@ -1415,7 +1419,7 @@ Before finishing, verify ALL of the following are true:
|
|
|
1415
1419
|
- [ ] Manifest file is written with \`prUrl\` field
|
|
1416
1420
|
If ANY item is unchecked, go back and complete it. Do NOT finish with incomplete steps.`;
|
|
1417
1421
|
}
|
|
1418
|
-
function buildImplementPrompt(issue, config, testRunner, pm, projectContext, cwd, manifestPath, repoContextMd, relevantFiles) {
|
|
1422
|
+
function buildImplementPrompt(issue, config, testRunner, pm, projectContext, cwd, manifestPath, repoContextMd, relevantFiles, lineageBlock) {
|
|
1419
1423
|
const workspace = resolve(config.workspace);
|
|
1420
1424
|
const resolvedManifestPath = manifestPath ?? getManifestPath(workspace);
|
|
1421
1425
|
if (config.workflow === "worktree") {
|
|
@@ -1430,7 +1434,8 @@ function buildImplementPrompt(issue, config, testRunner, pm, projectContext, cwd
|
|
|
1430
1434
|
cwd,
|
|
1431
1435
|
platform: config.platform,
|
|
1432
1436
|
repoContextMd,
|
|
1433
|
-
relevantFiles
|
|
1437
|
+
relevantFiles,
|
|
1438
|
+
lineageBlock
|
|
1434
1439
|
});
|
|
1435
1440
|
}
|
|
1436
1441
|
return buildPrompt({
|
|
@@ -1445,7 +1450,8 @@ function buildImplementPrompt(issue, config, testRunner, pm, projectContext, cwd
|
|
|
1445
1450
|
platform: config.platform,
|
|
1446
1451
|
repoContextMd,
|
|
1447
1452
|
config,
|
|
1448
|
-
relevantFiles
|
|
1453
|
+
relevantFiles,
|
|
1454
|
+
lineageBlock
|
|
1449
1455
|
});
|
|
1450
1456
|
}
|
|
1451
1457
|
function buildNativeWorktreePrompt(issue, repoPath, testRunner, pm, baseBranch, projectContext, manifestPath, platform2 = "cli", repoContextMd, relevantFiles) {
|
|
@@ -1731,7 +1737,7 @@ If ANY item is unchecked, go back and complete it. Do NOT finish with incomplete
|
|
|
1731
1737
|
// src/providers/aider.ts
|
|
1732
1738
|
import { mkdtempSync as mkdtempSync2, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
1733
1739
|
import { tmpdir as tmpdir2 } from "os";
|
|
1734
|
-
import { join as
|
|
1740
|
+
import { join as join5 } from "path";
|
|
1735
1741
|
|
|
1736
1742
|
// src/providers/output-buffer.ts
|
|
1737
1743
|
import { appendFileSync } from "fs";
|
|
@@ -1791,7 +1797,7 @@ var OutputBuffer = class {
|
|
|
1791
1797
|
import { execFile as execFile2, spawn as spawn3 } from "child_process";
|
|
1792
1798
|
import { mkdtempSync, rmSync, writeFileSync } from "fs";
|
|
1793
1799
|
import { tmpdir } from "os";
|
|
1794
|
-
import { join as
|
|
1800
|
+
import { join as join4 } from "path";
|
|
1795
1801
|
import { promisify as promisify2 } from "util";
|
|
1796
1802
|
|
|
1797
1803
|
// src/session/overseer.ts
|
|
@@ -1833,6 +1839,13 @@ function createSessionTimeout(proc, timeoutSeconds) {
|
|
|
1833
1839
|
};
|
|
1834
1840
|
}
|
|
1835
1841
|
|
|
1842
|
+
// src/session/activity.ts
|
|
1843
|
+
import { closeSync, openSync, readdirSync as readdirSync2, readSync, statSync as statSync2 } from "fs";
|
|
1844
|
+
import { homedir } from "os";
|
|
1845
|
+
import { join as join3 } from "path";
|
|
1846
|
+
var TAIL_BYTES = 128 * 1024;
|
|
1847
|
+
var DEFAULT_IDLE_THRESHOLD_MS = 5 * 60 * 1e3;
|
|
1848
|
+
|
|
1836
1849
|
// src/session/overseer.ts
|
|
1837
1850
|
var execFileAsync = promisify(execFile);
|
|
1838
1851
|
var STUCK_MESSAGE = "\n[lisa-overseer] Provider killed: no git changes detected within the stuck threshold. Eligible for fallback.\n";
|
|
@@ -2052,8 +2065,8 @@ async function isCommandAvailable(command, args = ["--version"]) {
|
|
|
2052
2065
|
}
|
|
2053
2066
|
async function runProviderProcess(config, prompt, opts) {
|
|
2054
2067
|
const start = Date.now();
|
|
2055
|
-
const tmpDir = mkdtempSync(
|
|
2056
|
-
const promptFile =
|
|
2068
|
+
const tmpDir = mkdtempSync(join4(tmpdir(), "lisa-"));
|
|
2069
|
+
const promptFile = join4(tmpDir, "prompt.md");
|
|
2057
2070
|
writeFileSync(promptFile, prompt, { encoding: "utf-8", mode: 384 });
|
|
2058
2071
|
try {
|
|
2059
2072
|
const promptCatExpr = `"$(cat '${escapeShellPath(promptFile)}')"`;
|
|
@@ -2180,8 +2193,8 @@ var AiderProvider = class {
|
|
|
2180
2193
|
try {
|
|
2181
2194
|
if (opts.model) validateShellArg(opts.model, "model");
|
|
2182
2195
|
const modelFlag = opts.model ? `--model ${opts.model}` : "";
|
|
2183
|
-
const aiderTmpDir = mkdtempSync2(
|
|
2184
|
-
const aiderPromptFile =
|
|
2196
|
+
const aiderTmpDir = mkdtempSync2(join5(tmpdir2(), "lisa-aider-"));
|
|
2197
|
+
const aiderPromptFile = join5(aiderTmpDir, "prompt.md");
|
|
2185
2198
|
writeFileSync2(aiderPromptFile, prompt, { encoding: "utf-8", mode: 384 });
|
|
2186
2199
|
const config = {
|
|
2187
2200
|
name: "aider",
|
|
@@ -4310,9 +4323,9 @@ function resolveModels(config) {
|
|
|
4310
4323
|
|
|
4311
4324
|
// src/session/context-manager.ts
|
|
4312
4325
|
import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
4313
|
-
import { join as
|
|
4326
|
+
import { join as join6 } from "path";
|
|
4314
4327
|
function getContextPath(dir) {
|
|
4315
|
-
return
|
|
4328
|
+
return join6(dir, ".lisa", "context.md");
|
|
4316
4329
|
}
|
|
4317
4330
|
function contextExists(dir) {
|
|
4318
4331
|
return existsSync3(getContextPath(dir));
|
|
@@ -4327,6 +4340,70 @@ function readContext(dir) {
|
|
|
4327
4340
|
}
|
|
4328
4341
|
}
|
|
4329
4342
|
|
|
4343
|
+
// src/plan/lineage.ts
|
|
4344
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync2, readdirSync as readdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
4345
|
+
import { join as join7 } from "path";
|
|
4346
|
+
function lineageDir(workspace) {
|
|
4347
|
+
return join7(workspace, ".lisa", "lineage");
|
|
4348
|
+
}
|
|
4349
|
+
function sanitizePlanId(planId) {
|
|
4350
|
+
return planId.replace(/[^a-zA-Z0-9_\-.]/g, "_");
|
|
4351
|
+
}
|
|
4352
|
+
function lineagePath(workspace, planId) {
|
|
4353
|
+
return join7(lineageDir(workspace), `${sanitizePlanId(planId)}.json`);
|
|
4354
|
+
}
|
|
4355
|
+
function saveLineage(workspace, lineage) {
|
|
4356
|
+
const dir = lineageDir(workspace);
|
|
4357
|
+
if (!existsSync4(dir)) {
|
|
4358
|
+
mkdirSync2(dir, { recursive: true });
|
|
4359
|
+
}
|
|
4360
|
+
const path = lineagePath(workspace, lineage.planId);
|
|
4361
|
+
writeFileSync4(path, JSON.stringify(lineage, null, " "), "utf-8");
|
|
4362
|
+
}
|
|
4363
|
+
function loadLineageForIssue(workspace, issueId) {
|
|
4364
|
+
const dir = lineageDir(workspace);
|
|
4365
|
+
if (!existsSync4(dir)) return null;
|
|
4366
|
+
let files;
|
|
4367
|
+
try {
|
|
4368
|
+
files = readdirSync3(dir).filter((f) => f.endsWith(".json"));
|
|
4369
|
+
} catch {
|
|
4370
|
+
return null;
|
|
4371
|
+
}
|
|
4372
|
+
for (const file of files) {
|
|
4373
|
+
try {
|
|
4374
|
+
const raw = readFileSync4(join7(dir, file), "utf-8");
|
|
4375
|
+
const lineage = JSON.parse(raw);
|
|
4376
|
+
if (lineage.issues.some((issue) => issue.id === issueId)) {
|
|
4377
|
+
return lineage;
|
|
4378
|
+
}
|
|
4379
|
+
} catch {
|
|
4380
|
+
}
|
|
4381
|
+
}
|
|
4382
|
+
return null;
|
|
4383
|
+
}
|
|
4384
|
+
function buildLineagePromptBlock(lineage, currentIssueId) {
|
|
4385
|
+
if (lineage.issues.length <= 1) return "";
|
|
4386
|
+
const sorted = [...lineage.issues].sort((a, b) => a.order - b.order);
|
|
4387
|
+
const taskList = sorted.map((issue, idx) => {
|
|
4388
|
+
const marker = issue.id === currentIssueId ? " <-- (this task)" : "";
|
|
4389
|
+
return ` ${idx + 1}. [${issue.id}] ${issue.title}${marker}`;
|
|
4390
|
+
}).join("\n");
|
|
4391
|
+
const siblings = sorted.filter((issue) => issue.id !== currentIssueId).map((issue) => `- [${issue.id}] ${issue.title}`).join("\n");
|
|
4392
|
+
return `## Task Hierarchy
|
|
4393
|
+
|
|
4394
|
+
**Goal:** ${lineage.goal}
|
|
4395
|
+
|
|
4396
|
+
This task is part of a decomposed plan with ${lineage.issues.length} subtasks:
|
|
4397
|
+
|
|
4398
|
+
${taskList}
|
|
4399
|
+
|
|
4400
|
+
## Parallel Work
|
|
4401
|
+
|
|
4402
|
+
The following sibling tasks may be running concurrently. Do NOT duplicate their work:
|
|
4403
|
+
|
|
4404
|
+
${siblings}`;
|
|
4405
|
+
}
|
|
4406
|
+
|
|
4330
4407
|
export {
|
|
4331
4408
|
analyzeProject,
|
|
4332
4409
|
runValidationCommands,
|
|
@@ -4359,5 +4436,8 @@ export {
|
|
|
4359
4436
|
contextExists,
|
|
4360
4437
|
readContext,
|
|
4361
4438
|
WATCH_POLL_INTERVAL_MS,
|
|
4362
|
-
resolveModels
|
|
4439
|
+
resolveModels,
|
|
4440
|
+
saveLineage,
|
|
4441
|
+
loadLineageForIssue,
|
|
4442
|
+
buildLineagePromptBlock
|
|
4363
4443
|
};
|