@tarcisiopgs/lisa 1.7.6 → 1.7.7
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 +5 -2
- package/dist/index.js +29 -9
- package/dist/{kanban-YP3TJJUT.js → kanban-5C3WZIKC.js} +28 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -85,6 +85,8 @@ Lisa follows a deterministic pipeline:
|
|
|
85
85
|
|
|
86
86
|
At least one provider must be installed and available in your PATH.
|
|
87
87
|
|
|
88
|
+
> **Cursor Free plan** — `lisa init` automatically detects Free accounts and restricts model selection to `auto` only. On paid plans, a curated list of top-tier models is shown (`composer-1.5`, `opus-4.6`, `sonnet-4.6`, `gpt-5.3-codex`, etc.).
|
|
89
|
+
|
|
88
90
|
### Fallback Chain
|
|
89
91
|
|
|
90
92
|
Configure multiple models — Lisa tries each in order. Transient errors (429, quota, timeout, network) trigger the next model; non-transient errors stop the chain.
|
|
@@ -183,12 +185,13 @@ When running in an interactive terminal, `lisa run` renders a real-time Kanban b
|
|
|
183
185
|
|-----|--------|
|
|
184
186
|
| `Tab` | Move to next column |
|
|
185
187
|
| `Shift+Tab` | Move to previous column |
|
|
186
|
-
| `↑` / `↓` | Navigate cards
|
|
188
|
+
| `↑` / `↓` | Navigate cards / scroll output |
|
|
187
189
|
| `Enter` | Open issue detail view (streams provider output) |
|
|
188
190
|
| `Esc` | Close detail view, return to board |
|
|
191
|
+
| `p` | Pause / resume — loop finishes the current issue then waits |
|
|
189
192
|
| `q` | Quit |
|
|
190
193
|
|
|
191
|
-
The terminal tab title also updates in real time: it shows a spinner with the active issue ID while work is in progress, and a checkmark when done.
|
|
194
|
+
The sidebar legend updates contextually: board shortcuts when browsing the Kanban, scroll and back hints when viewing issue detail. The terminal tab title also updates in real time: it shows a spinner with the active issue ID while work is in progress, and a checkmark when done.
|
|
192
195
|
|
|
193
196
|
## Configuration
|
|
194
197
|
|
package/dist/index.js
CHANGED
|
@@ -3154,6 +3154,13 @@ function createSource(name) {
|
|
|
3154
3154
|
var activeCleanup = null;
|
|
3155
3155
|
var activeProviderPid = null;
|
|
3156
3156
|
var shuttingDown = false;
|
|
3157
|
+
var loopPaused = false;
|
|
3158
|
+
kanbanEmitter.on("loop:pause", () => {
|
|
3159
|
+
loopPaused = true;
|
|
3160
|
+
});
|
|
3161
|
+
kanbanEmitter.on("loop:resume", () => {
|
|
3162
|
+
loopPaused = false;
|
|
3163
|
+
});
|
|
3157
3164
|
function resolveModels(config2) {
|
|
3158
3165
|
if (!config2.models || config2.models.length === 0) {
|
|
3159
3166
|
return [{ provider: config2.provider }];
|
|
@@ -3320,6 +3327,7 @@ async function runLoop(config2, opts) {
|
|
|
3320
3327
|
const timestamp2 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").substring(0, 19);
|
|
3321
3328
|
const logFile = resolve5(config2.logs.dir, `session_${session}_${timestamp2}.log`);
|
|
3322
3329
|
divider(session);
|
|
3330
|
+
await waitIfPaused();
|
|
3323
3331
|
startSpinner("fetching issue...");
|
|
3324
3332
|
if (opts.issueId) {
|
|
3325
3333
|
log(`Fetching issue '${opts.issueId}' from ${config2.source}...`);
|
|
@@ -4026,6 +4034,11 @@ async function cleanupWorktree(repoRoot, worktreePath) {
|
|
|
4026
4034
|
function sleep(ms) {
|
|
4027
4035
|
return new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
4028
4036
|
}
|
|
4037
|
+
async function waitIfPaused() {
|
|
4038
|
+
while (loopPaused) {
|
|
4039
|
+
await sleep(500);
|
|
4040
|
+
}
|
|
4041
|
+
}
|
|
4029
4042
|
|
|
4030
4043
|
// src/cli.ts
|
|
4031
4044
|
function sleep2(ms) {
|
|
@@ -4082,7 +4095,7 @@ Add them to your ${shell} and run: source ${shell}`));
|
|
|
4082
4095
|
if (isTUI) {
|
|
4083
4096
|
const { render } = await import("ink");
|
|
4084
4097
|
const { createElement } = await import("react");
|
|
4085
|
-
const { KanbanApp } = await import("./kanban-
|
|
4098
|
+
const { KanbanApp } = await import("./kanban-5C3WZIKC.js");
|
|
4086
4099
|
render(createElement(KanbanApp, { config: merged }), { exitOnCtrlC: false });
|
|
4087
4100
|
}
|
|
4088
4101
|
await runLoop(merged, {
|
|
@@ -4278,15 +4291,21 @@ var issue = defineCommand({
|
|
|
4278
4291
|
meta: { name: "issue", description: "Issue tracker operations for use inside worktrees" },
|
|
4279
4292
|
subCommands: { get: issueGet, done: issueDone }
|
|
4280
4293
|
});
|
|
4281
|
-
var
|
|
4294
|
+
var CURSOR_PREFERRED_MODELS = [
|
|
4282
4295
|
"auto",
|
|
4283
4296
|
"composer-1.5",
|
|
4297
|
+
"composer-1",
|
|
4298
|
+
"gpt-5.3-codex",
|
|
4299
|
+
"gpt-5.2",
|
|
4300
|
+
"gpt-5.1-codex-max",
|
|
4284
4301
|
"opus-4.6-thinking",
|
|
4285
4302
|
"opus-4.6",
|
|
4303
|
+
"sonnet-4.6-thinking",
|
|
4286
4304
|
"sonnet-4.6",
|
|
4287
|
-
"
|
|
4288
|
-
"
|
|
4289
|
-
"
|
|
4305
|
+
"gemini-3.1-pro",
|
|
4306
|
+
"gemini-3-pro",
|
|
4307
|
+
"grok",
|
|
4308
|
+
"kimi-k2.5"
|
|
4290
4309
|
];
|
|
4291
4310
|
function fetchCursorModels() {
|
|
4292
4311
|
try {
|
|
@@ -4298,13 +4317,14 @@ function fetchCursorModels() {
|
|
|
4298
4317
|
return false;
|
|
4299
4318
|
}
|
|
4300
4319
|
});
|
|
4301
|
-
if (!bin) return
|
|
4320
|
+
if (!bin) return CURSOR_PREFERRED_MODELS;
|
|
4302
4321
|
const raw = execSync8(`${bin} --list-models`, { encoding: "utf-8", timeout: 1e4 });
|
|
4303
4322
|
const clean = raw.replace(/\x1b\[[0-9;]*[mGKHFA-Z]/g, "");
|
|
4304
|
-
const
|
|
4305
|
-
|
|
4323
|
+
const all = clean.split("\n").map((l) => l.trim()).filter((l) => l.includes(" - ")).map((l) => (l.split(" - ")[0] ?? "").trim()).filter(Boolean);
|
|
4324
|
+
const filtered = CURSOR_PREFERRED_MODELS.filter((m) => all.includes(m));
|
|
4325
|
+
return filtered.length > 0 ? filtered : CURSOR_PREFERRED_MODELS;
|
|
4306
4326
|
} catch {
|
|
4307
|
-
return
|
|
4327
|
+
return CURSOR_PREFERRED_MODELS;
|
|
4308
4328
|
}
|
|
4309
4329
|
}
|
|
4310
4330
|
function fetchOpenCodeModels() {
|
|
@@ -337,11 +337,7 @@ function IssueDetail({ card, onBack }) {
|
|
|
337
337
|
] }) : visibleLines.map((line, i) => (
|
|
338
338
|
// biome-ignore lint/suspicious/noArrayIndexKey: log lines have no stable key
|
|
339
339
|
/* @__PURE__ */ jsx4(Text4, { color: "white", dimColor: true, children: line }, i)
|
|
340
|
-
)) })
|
|
341
|
-
/* @__PURE__ */ jsxs4(Box4, { justifyContent: "space-between", borderStyle: "single", borderColor: "gray", paddingX: 1, children: [
|
|
342
|
-
/* @__PURE__ */ jsx4(Text4, { color: "gray", dimColor: true, children: "[\u2191\u2193] scroll" }),
|
|
343
|
-
/* @__PURE__ */ jsx4(Text4, { color: "yellow", dimColor: true, children: "[Esc] back to board" })
|
|
344
|
-
] })
|
|
340
|
+
)) })
|
|
345
341
|
]
|
|
346
342
|
}
|
|
347
343
|
);
|
|
@@ -352,14 +348,15 @@ import { existsSync } from "fs";
|
|
|
352
348
|
import { basename, join } from "path";
|
|
353
349
|
import { Box as Box5, Text as Text5 } from "ink";
|
|
354
350
|
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
355
|
-
function Sidebar({ provider, source, cwd }) {
|
|
356
|
-
const dir = basename(cwd);
|
|
351
|
+
function Sidebar({ provider, source, cwd, activeView, paused = false }) {
|
|
352
|
+
const dir = basename(cwd).toUpperCase();
|
|
357
353
|
const cwdLabel = existsSync(join(cwd, ".git")) ? "REPOSITORY" : "WORKSPACE";
|
|
358
354
|
return /* @__PURE__ */ jsxs5(
|
|
359
355
|
Box5,
|
|
360
356
|
{
|
|
361
357
|
flexDirection: "column",
|
|
362
358
|
width: 28,
|
|
359
|
+
flexShrink: 0,
|
|
363
360
|
borderStyle: "single",
|
|
364
361
|
borderColor: "yellow",
|
|
365
362
|
paddingX: 1,
|
|
@@ -377,8 +374,8 @@ function Sidebar({ provider, source, cwd }) {
|
|
|
377
374
|
/* @__PURE__ */ jsx5(Text5, { color: "yellow", children: "\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D" })
|
|
378
375
|
] }),
|
|
379
376
|
/* @__PURE__ */ jsxs5(Box5, { marginBottom: 1, children: [
|
|
380
|
-
/* @__PURE__ */ jsx5(Text5, { color: "green", children: "\u25B6 " }),
|
|
381
|
-
/* @__PURE__ */ jsx5(Text5, { color: "green", bold: true, children: "RUNNING" })
|
|
377
|
+
/* @__PURE__ */ jsx5(Text5, { color: paused ? "yellow" : "green", children: paused ? "\u23F8 " : "\u25B6 " }),
|
|
378
|
+
/* @__PURE__ */ jsx5(Text5, { color: paused ? "yellow" : "green", bold: true, children: paused ? "PAUSED" : "RUNNING" })
|
|
382
379
|
] }),
|
|
383
380
|
/* @__PURE__ */ jsx5(Text5, { color: "yellow", children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
|
|
384
381
|
/* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 1, children: [
|
|
@@ -404,11 +401,15 @@ function Sidebar({ provider, source, cwd }) {
|
|
|
404
401
|
] }),
|
|
405
402
|
/* @__PURE__ */ jsx5(Box5, { flexGrow: 1 }),
|
|
406
403
|
/* @__PURE__ */ jsx5(Text5, { color: "yellow", children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
|
|
407
|
-
/* @__PURE__ */ jsxs5(Box5, { marginTop: 1, flexDirection: "column", children: [
|
|
404
|
+
activeView === "board" ? /* @__PURE__ */ jsxs5(Box5, { marginTop: 1, flexDirection: "column", children: [
|
|
408
405
|
/* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "[Tab] next column" }),
|
|
409
406
|
/* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "[\u2191\u2193] navigate " }),
|
|
410
407
|
/* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "[\u21B5] view detail " }),
|
|
408
|
+
/* @__PURE__ */ jsx5(Text5, { dimColor: true, children: paused ? "[p] resume " : "[p] pause " }),
|
|
411
409
|
/* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "[q] quit " })
|
|
410
|
+
] }) : /* @__PURE__ */ jsxs5(Box5, { marginTop: 1, flexDirection: "column", children: [
|
|
411
|
+
/* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "[\u2191\u2193] scroll " }),
|
|
412
|
+
/* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "[Esc] back to board" })
|
|
412
413
|
] })
|
|
413
414
|
]
|
|
414
415
|
}
|
|
@@ -423,6 +424,7 @@ function KanbanApp({ config }) {
|
|
|
423
424
|
const [activeView, setActiveView] = useState3("board");
|
|
424
425
|
const [activeColIndex, setActiveColIndex] = useState3(0);
|
|
425
426
|
const [activeCardIndex, setActiveCardIndex] = useState3(0);
|
|
427
|
+
const [paused, setPaused] = useState3(false);
|
|
426
428
|
useEffect3(() => {
|
|
427
429
|
const onExit = () => exit();
|
|
428
430
|
kanbanEmitter.on("tui:exit", onExit);
|
|
@@ -454,6 +456,12 @@ function KanbanApp({ config }) {
|
|
|
454
456
|
if (key.escape) setActiveView("board");
|
|
455
457
|
return;
|
|
456
458
|
}
|
|
459
|
+
if (input === "p") {
|
|
460
|
+
const next = !paused;
|
|
461
|
+
setPaused(next);
|
|
462
|
+
kanbanEmitter.emit(next ? "loop:pause" : "loop:resume");
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
457
465
|
if (key.tab && !key.shift) {
|
|
458
466
|
const nextCol = (activeColIndex + 1) % 3;
|
|
459
467
|
setActiveColIndex(nextCol);
|
|
@@ -489,7 +497,16 @@ function KanbanApp({ config }) {
|
|
|
489
497
|
};
|
|
490
498
|
const selectedCard = activeView === "detail" ? columnCards[activeColIndex]?.[activeCardIndex] ?? null : null;
|
|
491
499
|
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "row", height: process.stdout.rows, children: [
|
|
492
|
-
/* @__PURE__ */ jsx6(
|
|
500
|
+
/* @__PURE__ */ jsx6(
|
|
501
|
+
Sidebar,
|
|
502
|
+
{
|
|
503
|
+
provider: config.provider,
|
|
504
|
+
source: config.source,
|
|
505
|
+
cwd: process.cwd(),
|
|
506
|
+
activeView,
|
|
507
|
+
paused
|
|
508
|
+
}
|
|
509
|
+
),
|
|
493
510
|
activeView === "board" || !selectedCard ? /* @__PURE__ */ jsx6(
|
|
494
511
|
Board,
|
|
495
512
|
{
|