@tarcisiopgs/lisa 1.7.0 → 1.7.2

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/dist/index.js CHANGED
@@ -317,7 +317,9 @@ function error(message) {
317
317
  emitJson("error", message);
318
318
  return;
319
319
  }
320
- console.error(`${pc.red("[lisa]")} ${pc.dim(timestamp())} ${message}`);
320
+ if (shouldPrintToConsole()) {
321
+ console.error(`${pc.red("[lisa]")} ${pc.dim(timestamp())} ${message}`);
322
+ }
321
323
  writeToFile("error", message);
322
324
  }
323
325
  function ok(message) {
@@ -3285,8 +3287,14 @@ function installSignalHandlers() {
3285
3287
  `Failed to revert ${issueId}: ${err instanceof Error ? err.message : String(err)}`
3286
3288
  );
3287
3289
  }
3290
+ kanbanEmitter.emit("issue:reverted", issueId);
3291
+ }
3292
+ const hasTUI = kanbanEmitter.listenerCount("tui:exit") > 0;
3293
+ kanbanEmitter.emit("tui:exit");
3294
+ if (hasTUI) {
3295
+ await new Promise((resolve6) => setTimeout(resolve6, 250));
3288
3296
  }
3289
- process.exit(1);
3297
+ process.exit(0);
3290
3298
  };
3291
3299
  process.on("SIGINT", () => {
3292
3300
  cleanup("SIGINT");
@@ -4114,7 +4122,7 @@ Add them to your ${shell} and run: source ${shell}`));
4114
4122
  if (isTUI) {
4115
4123
  const { render } = await import("ink");
4116
4124
  const { createElement } = await import("react");
4117
- const { KanbanApp } = await import("./kanban-UW2MC2PB.js");
4125
+ const { KanbanApp } = await import("./kanban-BY7QNVEE.js");
4118
4126
  render(createElement(KanbanApp, { config: merged }), { exitOnCtrlC: false });
4119
4127
  }
4120
4128
  await runLoop(merged, {
@@ -4164,7 +4172,7 @@ var init = defineCommand({
4164
4172
  }
4165
4173
  if (configExists()) {
4166
4174
  const overwrite = await clack.confirm({
4167
- message: "Config already exists. Overwrite?"
4175
+ message: "A config already exists at .lisa/config.yaml. Overwrite it?"
4168
4176
  });
4169
4177
  if (clack.isCancel(overwrite) || !overwrite) {
4170
4178
  log("Cancelled.");
@@ -4335,6 +4343,7 @@ var main = defineCommand({
4335
4343
  });
4336
4344
  async function runConfigWizard() {
4337
4345
  banner();
4346
+ clack.intro(pc2.cyan(" lisa \u2014 autonomous issue resolver "));
4338
4347
  const providerLabels = {
4339
4348
  claude: "Claude Code",
4340
4349
  gemini: "Gemini CLI",
@@ -4350,25 +4359,26 @@ async function runConfigWizard() {
4350
4359
  };
4351
4360
  const available = await getAvailableProviders();
4352
4361
  if (available.length === 0) {
4353
- clack.log.error("No compatible AI providers found.");
4362
+ clack.log.error("No AI provider found on your system.");
4354
4363
  clack.log.info(
4355
- `Install at least one of the following providers to continue:
4364
+ `Install at least one of the following and re-run ${pc2.cyan("lisa init")}:
4356
4365
 
4357
- ${pc2.bold("Claude Code")} ${pc2.dim("npm i -g @anthropic-ai/claude-code")}
4358
- ${pc2.bold("Gemini CLI")} ${pc2.dim("npm i -g @anthropic-ai/gemini-cli")}
4359
- ${pc2.bold("OpenCode")} ${pc2.dim("npm i -g opencode")}
4360
-
4361
- After installing, run ${pc2.cyan("lisa init")} again.`
4366
+ ${pc2.bold("Claude Code")} ${pc2.dim("npm i -g @anthropic-ai/claude-code")}
4367
+ ${pc2.bold("Gemini CLI")} ${pc2.dim("npm i -g @google/gemini-cli")}
4368
+ ${pc2.bold("OpenCode")} ${pc2.dim("npm i -g opencode")}
4369
+ ${pc2.bold("GitHub Copilot CLI")} ${pc2.dim("npm i -g @github/copilot-cli")}
4370
+ ${pc2.bold("Goose")} ${pc2.dim("https://block.github.io/goose")}
4371
+ ${pc2.bold("Aider")} ${pc2.dim("pip install aider-chat")}`
4362
4372
  );
4363
4373
  return process.exit(1);
4364
4374
  }
4365
4375
  let providerName;
4366
4376
  if (available.length === 1 && available[0]) {
4367
4377
  providerName = available[0].name;
4368
- clack.log.info(`Found provider: ${pc2.bold(providerLabels[providerName])}`);
4378
+ clack.log.info(`Auto-detected ${pc2.bold(providerLabels[providerName])} as your AI provider.`);
4369
4379
  } else {
4370
4380
  const selected = await clack.select({
4371
- message: "Which AI provider do you want to use?",
4381
+ message: "Which AI provider should resolve your issues?",
4372
4382
  options: available.map((p) => ({
4373
4383
  value: p.name,
4374
4384
  label: providerLabels[p.name]
@@ -4383,14 +4393,14 @@ After installing, run ${pc2.cyan("lisa init")} again.`
4383
4393
  const isFree = await isCursorFreePlan();
4384
4394
  if (isFree) {
4385
4395
  availableModels = ["auto"];
4386
- clack.log.info("Cursor Free plan detected. Using 'auto' model only.");
4396
+ clack.log.info("Cursor Free plan detected \u2014 only the 'auto' model is available.");
4387
4397
  } else {
4388
4398
  availableModels = CURSOR_MODELS;
4389
4399
  }
4390
4400
  }
4391
4401
  if (availableModels && availableModels.length > 0) {
4392
4402
  const modelSelection = await clack.multiselect({
4393
- message: "Which models to use? Select in order: primary first, then fallbacks",
4403
+ message: "Which models should Lisa use? Select in order \u2014 first = primary, rest = fallbacks",
4394
4404
  options: availableModels.map((m) => ({
4395
4405
  value: m,
4396
4406
  label: m
@@ -4401,10 +4411,15 @@ After installing, run ${pc2.cyan("lisa init")} again.`
4401
4411
  selectedModels = modelSelection ?? [];
4402
4412
  }
4403
4413
  const source = await clack.select({
4404
- message: "Where do your issues live?",
4414
+ message: "Where do your issues come from?",
4405
4415
  options: [
4406
- { value: "linear", label: "Linear" },
4407
- { value: "trello", label: "Trello" }
4416
+ { value: "linear", label: "Linear", hint: "GraphQL API" },
4417
+ { value: "trello", label: "Trello", hint: "REST API" },
4418
+ { value: "github", label: "GitHub Issues", hint: "REST API" },
4419
+ { value: "gitlab", label: "GitLab Issues", hint: "REST API" },
4420
+ { value: "plane", label: "Plane", hint: "REST API" },
4421
+ { value: "shortcut", label: "Shortcut", hint: "REST API" },
4422
+ { value: "jira", label: "Jira", hint: "REST API" }
4408
4423
  ]
4409
4424
  });
4410
4425
  if (clack.isCancel(source)) return process.exit(0);
@@ -4412,24 +4427,27 @@ After installing, run ${pc2.cyan("lisa init")} again.`
4412
4427
  if (missing.length > 0) {
4413
4428
  const shell = process.env.SHELL?.includes("zsh") ? "~/.zshrc" : "~/.bashrc";
4414
4429
  clack.log.warning(
4415
- `Missing environment variables:
4430
+ `The following environment variables are missing:
4431
+
4416
4432
  ${missing.map((v) => ` ${pc2.bold(v)}`).join("\n")}
4417
4433
 
4418
- Add them to your environment variables:
4419
- ${missing.map((v) => ` export ${v}="your-key-here"`).join("\n")}
4434
+ Add them to ${pc2.cyan(shell)}:
4435
+ ${missing.map((v) => ` export ${v}="your-value-here"`).join("\n")}
4420
4436
 
4421
- Then run: ${pc2.cyan(`source ${shell}`)}`
4437
+ Then reload: ${pc2.cyan(`source ${shell}`)}`
4422
4438
  );
4423
4439
  }
4424
4440
  const githubMethod = await detectGitHubMethod();
4425
4441
  const teamAnswer = await clack.text({
4426
- message: source === "linear" ? "Team?" : "Board?"
4442
+ message: source === "linear" ? "What is your Linear team name?" : source === "trello" ? "What is your Trello board name?" : source === "jira" ? "What is your Jira project key?" : "What is your team or project name?",
4443
+ placeholder: source === "linear" ? "e.g. Engineering" : void 0
4427
4444
  });
4428
4445
  if (clack.isCancel(teamAnswer)) return process.exit(0);
4429
4446
  const team = teamAnswer;
4430
4447
  const labelAnswer = await clack.text({
4431
- message: "Label to pick up?",
4432
- initialValue: "ready"
4448
+ message: "Which label marks issues as ready for the agent to pick up?",
4449
+ initialValue: "ready",
4450
+ placeholder: "e.g. ready, ai, lisa"
4433
4451
  });
4434
4452
  if (clack.isCancel(labelAnswer)) return process.exit(0);
4435
4453
  const label = labelAnswer;
@@ -4446,47 +4464,57 @@ Then run: ${pc2.cyan(`source ${shell}`)}`
4446
4464
  pickFrom = pickFromAnswer;
4447
4465
  project = pickFrom;
4448
4466
  const inProgressAnswer = await clack.text({
4449
- message: "Move to which column while working?",
4467
+ message: "Move the card to which list while the agent is working?",
4450
4468
  initialValue: "In Progress"
4451
4469
  });
4452
4470
  if (clack.isCancel(inProgressAnswer)) return process.exit(0);
4453
4471
  inProgress = inProgressAnswer;
4454
4472
  const doneAnswer = await clack.text({
4455
- message: "Move to which column after PR?",
4473
+ message: "Move the card to which list after the PR is created?",
4456
4474
  initialValue: "Code Review"
4457
4475
  });
4458
4476
  if (clack.isCancel(doneAnswer)) return process.exit(0);
4459
4477
  done = doneAnswer;
4460
4478
  } else {
4461
4479
  const projectAnswer = await clack.text({
4462
- message: "Project?"
4480
+ message: source === "linear" ? "Which Linear project should Lisa work on? (leave empty for all team issues)" : "Which project should Lisa work on?",
4481
+ placeholder: source === "linear" ? "e.g. Q1 Roadmap (optional)" : void 0
4463
4482
  });
4464
4483
  if (clack.isCancel(projectAnswer)) return process.exit(0);
4465
4484
  project = projectAnswer;
4466
4485
  const pickFromAnswer = await clack.text({
4467
- message: "Pick up issues from which status?",
4468
- initialValue: "Backlog"
4486
+ message: "Pick up issues in which status?",
4487
+ initialValue: "Backlog",
4488
+ placeholder: "e.g. Backlog, Todo"
4469
4489
  });
4470
4490
  if (clack.isCancel(pickFromAnswer)) return process.exit(0);
4471
4491
  pickFrom = pickFromAnswer;
4472
4492
  const inProgressAnswer = await clack.text({
4473
- message: "Move to which status while working?",
4493
+ message: "Move to which status while the agent is working?",
4474
4494
  initialValue: "In Progress"
4475
4495
  });
4476
4496
  if (clack.isCancel(inProgressAnswer)) return process.exit(0);
4477
4497
  inProgress = inProgressAnswer;
4478
4498
  const doneAnswer = await clack.text({
4479
- message: "Move to which status after PR?",
4499
+ message: "Move to which status after the PR is created?",
4480
4500
  initialValue: "In Review"
4481
4501
  });
4482
4502
  if (clack.isCancel(doneAnswer)) return process.exit(0);
4483
4503
  done = doneAnswer;
4484
4504
  }
4485
4505
  const workflowAnswer = await clack.select({
4486
- message: "How should Lisa work on issues?",
4506
+ message: "How should Lisa check out code for each issue?",
4487
4507
  options: [
4488
- { value: "branch", label: "Branch", hint: "creates branches in the current checkout" },
4489
- { value: "worktree", label: "Worktree", hint: "creates isolated worktrees per issue" }
4508
+ {
4509
+ value: "worktree",
4510
+ label: "Worktree",
4511
+ hint: "isolated git worktree per issue \u2014 recommended"
4512
+ },
4513
+ {
4514
+ value: "branch",
4515
+ label: "Branch",
4516
+ hint: "new branch in the current checkout"
4517
+ }
4490
4518
  ]
4491
4519
  });
4492
4520
  if (clack.isCancel(workflowAnswer)) return process.exit(0);
@@ -4497,7 +4525,7 @@ Then run: ${pc2.cyan(`source ${shell}`)}`
4497
4525
  if (repos.length === 0) {
4498
4526
  const detected = detectDefaultBranch(cwd);
4499
4527
  const branchAnswer = await clack.text({
4500
- message: "Base branch?",
4528
+ message: "What is the base branch to branch off from?",
4501
4529
  initialValue: detected
4502
4530
  });
4503
4531
  if (clack.isCancel(branchAnswer)) return process.exit(0);
@@ -4507,7 +4535,7 @@ Then run: ${pc2.cyan(`source ${shell}`)}`
4507
4535
  const repoPath = resolvePath(cwd, repo.path);
4508
4536
  const detected = detectDefaultBranch(repoPath);
4509
4537
  const branchAnswer = await clack.text({
4510
- message: `Base branch for ${repo.name}?`,
4538
+ message: `Base branch for ${pc2.bold(repo.name)}?`,
4511
4539
  initialValue: detected
4512
4540
  });
4513
4541
  if (clack.isCancel(branchAnswer)) return process.exit(0);
@@ -4522,7 +4550,7 @@ Then run: ${pc2.cyan(`source ${shell}`)}`
4522
4550
  ensureWorktreeGitignore(resolvePath(cwd, repo.path));
4523
4551
  }
4524
4552
  }
4525
- clack.log.info("Added .worktrees to .gitignore");
4553
+ clack.log.info("Added .worktrees/ to .gitignore");
4526
4554
  }
4527
4555
  const cfg = {
4528
4556
  provider: providerName,
@@ -4545,28 +4573,31 @@ Then run: ${pc2.cyan(`source ${shell}`)}`
4545
4573
  logs: { dir: ".lisa/logs", format: "text" }
4546
4574
  };
4547
4575
  saveConfig(cfg);
4548
- clack.outro(pc2.green("Config saved to .lisa/config.yaml"));
4576
+ clack.outro(
4577
+ `${pc2.green("All set!")} Config saved to ${pc2.cyan(".lisa/config.yaml")}
4578
+ Run ${pc2.bold(pc2.cyan("lisa run"))} to start resolving issues.`
4579
+ );
4549
4580
  }
4550
4581
  async function detectGitHubMethod() {
4551
4582
  const hasToken = !!process.env.GITHUB_TOKEN;
4552
4583
  const hasCli = await isGhCliAvailable();
4553
4584
  if (hasToken && hasCli) {
4554
4585
  const selected = await clack.select({
4555
- message: "Both GitHub CLI and GITHUB_TOKEN detected. Which do you want to use?",
4586
+ message: "How should Lisa create pull requests?",
4556
4587
  options: [
4557
- { value: "cli", label: "GitHub CLI", hint: "gh" },
4558
- { value: "token", label: "GitHub API", hint: "GITHUB_TOKEN" }
4588
+ { value: "cli", label: "GitHub CLI", hint: "uses `gh pr create` \u2014 recommended" },
4589
+ { value: "token", label: "GitHub API", hint: "uses GITHUB_TOKEN directly" }
4559
4590
  ]
4560
4591
  });
4561
4592
  if (clack.isCancel(selected)) return process.exit(0);
4562
4593
  return selected;
4563
4594
  }
4564
4595
  if (hasCli) {
4565
- clack.log.info("Using GitHub CLI for pull requests.");
4596
+ clack.log.info("Pull requests will be created using the GitHub CLI.");
4566
4597
  return "cli";
4567
4598
  }
4568
4599
  if (hasToken) {
4569
- clack.log.info("Using GITHUB_TOKEN for pull requests.");
4600
+ clack.log.info("Pull requests will be created using GITHUB_TOKEN.");
4570
4601
  return "token";
4571
4602
  }
4572
4603
  return "token";
@@ -4574,7 +4605,7 @@ async function detectGitHubMethod() {
4574
4605
  async function detectGitRepos() {
4575
4606
  const cwd = process.cwd();
4576
4607
  if (existsSync7(join12(cwd, ".git"))) {
4577
- clack.log.info(`Detected git repository in current directory.`);
4608
+ clack.log.info("Found a git repository in the current directory.");
4578
4609
  return [];
4579
4610
  }
4580
4611
  const entries = readdirSync(cwd, { withFileTypes: true });
@@ -4583,7 +4614,7 @@ async function detectGitRepos() {
4583
4614
  return [];
4584
4615
  }
4585
4616
  const selected = await clack.multiselect({
4586
- message: "Select the repos to include in the workspace:",
4617
+ message: "Multiple git repositories found \u2014 which ones should Lisa work on?",
4587
4618
  options: gitDirs.map((dir) => ({ value: dir, label: dir }))
4588
4619
  });
4589
4620
  if (clack.isCancel(selected)) return process.exit(0);
@@ -1,11 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ kanbanEmitter,
3
4
  useKanbanState
4
5
  } from "./chunk-MUBWKMRZ.js";
5
6
 
6
7
  // src/ui/kanban.tsx
7
8
  import { Box as Box6, useApp, useInput as useInput2 } from "ink";
8
- import { useState as useState3 } from "react";
9
+ import { useEffect as useEffect3, useState as useState3 } from "react";
9
10
 
10
11
  // src/ui/board.tsx
11
12
  import { Box as Box3, Text as Text3 } from "ink";
@@ -283,8 +284,9 @@ function IssueDetail({ card, onBack }) {
283
284
  } else if (card.column === "done" && card.startedAt !== void 0 && card.finishedAt !== void 0) {
284
285
  elapsedDisplay = formatElapsed2(card.finishedAt - card.startedAt);
285
286
  }
286
- const innerWidth = Math.max(0, terminalCols - 6);
287
- const separator = `\u2560${"\u2550".repeat(innerWidth)}\u2563`;
287
+ const SIDEBAR_TOTAL_WIDTH = 28;
288
+ const separatorInner = Math.max(0, terminalCols - SIDEBAR_TOTAL_WIDTH - 4);
289
+ const separator = `\u2560${"\u2550".repeat(Math.max(0, separatorInner - 2))}\u2563`;
288
290
  const totalLines = lines.length;
289
291
  const scrollPct = totalLines <= bodyRows ? "100%" : `${Math.round((startLine + bodyRows) / totalLines * 100)}%`;
290
292
  return /* @__PURE__ */ jsxs4(
@@ -413,6 +415,13 @@ function KanbanApp({ config }) {
413
415
  const [activeView, setActiveView] = useState3("board");
414
416
  const [activeColIndex, setActiveColIndex] = useState3(0);
415
417
  const [activeCardIndex, setActiveCardIndex] = useState3(0);
418
+ useEffect3(() => {
419
+ const onExit = () => exit();
420
+ kanbanEmitter.on("tui:exit", onExit);
421
+ return () => {
422
+ kanbanEmitter.off("tui:exit", onExit);
423
+ };
424
+ }, [exit]);
416
425
  const backlog = cards.filter((c) => c.column === "backlog");
417
426
  const inProgress = cards.filter((c) => c.column === "in_progress");
418
427
  const done = cards.filter((c) => c.column === "done");
@@ -420,7 +429,6 @@ function KanbanApp({ config }) {
420
429
  useInput2((input, key) => {
421
430
  if (input === "q") {
422
431
  process.emit("SIGINT");
423
- exit();
424
432
  return;
425
433
  }
426
434
  if (activeView === "detail") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tarcisiopgs/lisa",
3
- "version": "1.7.0",
3
+ "version": "1.7.2",
4
4
  "description": "Deterministic autonomous issue resolver — structured AI agent loop for Linear/Trello",
5
5
  "license": "MIT",
6
6
  "type": "module",