@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 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 | `n` | Open plan mode |
322
- | `↵` | Open detail view | `r` | Run (from idle) |
323
- | `p` | Pause / resume | `q` | Quit |
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-PPRXJHPW.js";
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 join4 } from "path";
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 join3 } from "path";
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(join3(tmpdir(), "lisa-"));
2056
- const promptFile = join3(tmpDir, "prompt.md");
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(join4(tmpdir2(), "lisa-aider-"));
2184
- const aiderPromptFile = join4(aiderTmpDir, "prompt.md");
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 join5 } from "path";
4326
+ import { join as join6 } from "path";
4314
4327
  function getContextPath(dir) {
4315
- return join5(dir, ".lisa", "context.md");
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
  };