@tarcisiopgs/lisa 1.7.6 → 1.8.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
@@ -82,9 +82,12 @@ Lisa follows a deterministic pipeline:
82
82
  | Cursor Agent | `cursor` | `agent` / `cursor-agent` |
83
83
  | Goose | `goose` | `goose` |
84
84
  | Aider | `aider` | `aider` |
85
+ | OpenAI Codex | `codex` | `codex` |
85
86
 
86
87
  At least one provider must be installed and available in your PATH.
87
88
 
89
+ > **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.).
90
+
88
91
  ### Fallback Chain
89
92
 
90
93
  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 +186,13 @@ When running in an interactive terminal, `lisa run` renders a real-time Kanban b
183
186
  |-----|--------|
184
187
  | `Tab` | Move to next column |
185
188
  | `Shift+Tab` | Move to previous column |
186
- | `↑` / `↓` | Navigate cards within a column |
189
+ | `↑` / `↓` | Navigate cards / scroll output |
187
190
  | `Enter` | Open issue detail view (streams provider output) |
188
191
  | `Esc` | Close detail view, return to board |
192
+ | `p` | Pause / resume — loop finishes the current issue then waits |
189
193
  | `q` | Quit |
190
194
 
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.
195
+ 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
196
 
193
197
  ## Configuration
194
198
 
package/dist/index.js CHANGED
@@ -9,10 +9,10 @@ import {
9
9
  } from "./chunk-YZKNBQN6.js";
10
10
 
11
11
  // src/cli.ts
12
- import { execSync as execSync8 } from "child_process";
12
+ import { execSync as execSync9 } from "child_process";
13
13
  import { existsSync as existsSync7, readdirSync, readFileSync as readFileSync6 } from "fs";
14
- import { tmpdir as tmpdir8 } from "os";
15
- import { join as join12, resolve as resolvePath } from "path";
14
+ import { tmpdir as tmpdir9 } from "os";
15
+ import { join as join13, resolve as resolvePath } from "path";
16
16
  import * as clack from "@clack/prompts";
17
17
  import { defineCommand, runMain } from "citty";
18
18
  import pc2 from "picocolors";
@@ -186,7 +186,8 @@ var PROVIDER_DISPLAY_NAMES = {
186
186
  copilot: "GitHub Copilot CLI",
187
187
  cursor: "Cursor Agent",
188
188
  goose: "Goose",
189
- aider: "Aider"
189
+ aider: "Aider",
190
+ codex: "OpenAI Codex"
190
191
  };
191
192
  function formatProviderName(providerUsed) {
192
193
  const providerKey = providerUsed.split("/")[0] ?? providerUsed;
@@ -281,8 +282,8 @@ function determineRepoPath(repos, issue2, workspace) {
281
282
  }
282
283
 
283
284
  // src/loop.ts
284
- import { appendFileSync as appendFileSync10, existsSync as existsSync6, readFileSync as readFileSync5, unlinkSync as unlinkSync8 } from "fs";
285
- import { join as join11, resolve as resolve5 } from "path";
285
+ import { appendFileSync as appendFileSync11, existsSync as existsSync6, readFileSync as readFileSync5, unlinkSync as unlinkSync9 } from "fs";
286
+ import { join as join12, resolve as resolve5 } from "path";
286
287
  import { execa as execa3 } from "execa";
287
288
 
288
289
  // src/output/logger.ts
@@ -1129,16 +1130,16 @@ var ClaudeProvider = class {
1129
1130
  }
1130
1131
  };
1131
1132
 
1132
- // src/providers/copilot.ts
1133
+ // src/providers/codex.ts
1133
1134
  import { execSync as execSync3, spawn as spawn3 } from "child_process";
1134
1135
  import { appendFileSync as appendFileSync5, mkdtempSync as mkdtempSync3, unlinkSync as unlinkSync3, writeFileSync as writeFileSync6 } from "fs";
1135
1136
  import { tmpdir as tmpdir3 } from "os";
1136
1137
  import { join as join6 } from "path";
1137
- var CopilotProvider = class {
1138
- name = "copilot";
1138
+ var CodexProvider = class {
1139
+ name = "codex";
1139
1140
  async isAvailable() {
1140
1141
  try {
1141
- execSync3("copilot version", { stdio: "ignore" });
1142
+ execSync3("codex --version", { stdio: "ignore" });
1142
1143
  return true;
1143
1144
  } catch {
1144
1145
  return false;
@@ -1150,9 +1151,12 @@ var CopilotProvider = class {
1150
1151
  const promptFile = join6(tmpDir, "prompt.md");
1151
1152
  writeFileSync6(promptFile, prompt, "utf-8");
1152
1153
  try {
1153
- const proc = spawn3("sh", ["-c", `copilot --allow-all -p "$(cat '${promptFile}')"`], {
1154
+ const modelFlag = opts.model ? `--model ${opts.model}` : "";
1155
+ const cmd = `codex exec --dangerously-bypass-approvals-and-sandbox --ephemeral ${modelFlag} "$(cat '${promptFile}')"`;
1156
+ const proc = spawn3("sh", ["-c", cmd], {
1154
1157
  cwd: opts.cwd,
1155
- stdio: ["ignore", "pipe", "pipe"]
1158
+ stdio: ["ignore", "pipe", "pipe"],
1159
+ env: { ...process.env, CODEX_QUIET_MODE: "1" }
1156
1160
  });
1157
1161
  if (proc.pid) opts.onProcess?.(proc.pid);
1158
1162
  const overseer = opts.overseer?.enabled ? startOverseer(proc, opts.cwd, opts.overseer) : null;
@@ -1206,15 +1210,92 @@ var CopilotProvider = class {
1206
1210
  }
1207
1211
  };
1208
1212
 
1209
- // src/providers/cursor.ts
1213
+ // src/providers/copilot.ts
1210
1214
  import { execSync as execSync4, spawn as spawn4 } from "child_process";
1211
1215
  import { appendFileSync as appendFileSync6, mkdtempSync as mkdtempSync4, unlinkSync as unlinkSync4, writeFileSync as writeFileSync7 } from "fs";
1212
1216
  import { tmpdir as tmpdir4 } from "os";
1213
1217
  import { join as join7 } from "path";
1218
+ var CopilotProvider = class {
1219
+ name = "copilot";
1220
+ async isAvailable() {
1221
+ try {
1222
+ execSync4("copilot version", { stdio: "ignore" });
1223
+ return true;
1224
+ } catch {
1225
+ return false;
1226
+ }
1227
+ }
1228
+ async run(prompt, opts) {
1229
+ const start = Date.now();
1230
+ const tmpDir = mkdtempSync4(join7(tmpdir4(), "lisa-"));
1231
+ const promptFile = join7(tmpDir, "prompt.md");
1232
+ writeFileSync7(promptFile, prompt, "utf-8");
1233
+ try {
1234
+ const proc = spawn4("sh", ["-c", `copilot --allow-all -p "$(cat '${promptFile}')"`], {
1235
+ cwd: opts.cwd,
1236
+ stdio: ["ignore", "pipe", "pipe"]
1237
+ });
1238
+ if (proc.pid) opts.onProcess?.(proc.pid);
1239
+ const overseer = opts.overseer?.enabled ? startOverseer(proc, opts.cwd, opts.overseer) : null;
1240
+ const chunks = [];
1241
+ proc.stdout.on("data", (chunk) => {
1242
+ const text2 = chunk.toString();
1243
+ if (getOutputMode() !== "tui") process.stdout.write(text2);
1244
+ if (opts.issueId) {
1245
+ kanbanEmitter.emit("issue:output", opts.issueId, text2);
1246
+ }
1247
+ chunks.push(text2);
1248
+ try {
1249
+ appendFileSync6(opts.logFile, text2);
1250
+ } catch {
1251
+ }
1252
+ });
1253
+ proc.stderr.on("data", (chunk) => {
1254
+ const text2 = chunk.toString();
1255
+ if (getOutputMode() !== "tui") process.stderr.write(text2);
1256
+ try {
1257
+ appendFileSync6(opts.logFile, text2);
1258
+ } catch {
1259
+ }
1260
+ });
1261
+ const exitCode = await new Promise((resolve6) => {
1262
+ proc.on("close", (code) => {
1263
+ overseer?.stop();
1264
+ resolve6(code ?? 1);
1265
+ });
1266
+ });
1267
+ if (overseer?.wasKilled()) {
1268
+ chunks.push(STUCK_MESSAGE);
1269
+ }
1270
+ return {
1271
+ success: exitCode === 0 && !overseer?.wasKilled(),
1272
+ output: chunks.join(""),
1273
+ duration: Date.now() - start
1274
+ };
1275
+ } catch (err) {
1276
+ return {
1277
+ success: false,
1278
+ output: err instanceof Error ? err.message : String(err),
1279
+ duration: Date.now() - start
1280
+ };
1281
+ } finally {
1282
+ try {
1283
+ unlinkSync4(promptFile);
1284
+ } catch {
1285
+ }
1286
+ }
1287
+ }
1288
+ };
1289
+
1290
+ // src/providers/cursor.ts
1291
+ import { execSync as execSync5, spawn as spawn5 } from "child_process";
1292
+ import { appendFileSync as appendFileSync7, mkdtempSync as mkdtempSync5, unlinkSync as unlinkSync5, writeFileSync as writeFileSync8 } from "fs";
1293
+ import { tmpdir as tmpdir5 } from "os";
1294
+ import { join as join8 } from "path";
1214
1295
  function findCursorBinary() {
1215
1296
  for (const bin of ["agent", "cursor-agent"]) {
1216
1297
  try {
1217
- execSync4(`${bin} --version`, { stdio: "ignore" });
1298
+ execSync5(`${bin} --version`, { stdio: "ignore" });
1218
1299
  return bin;
1219
1300
  } catch {
1220
1301
  }
@@ -1236,12 +1317,12 @@ var CursorProvider = class {
1236
1317
  duration: Date.now() - start
1237
1318
  };
1238
1319
  }
1239
- const tmpDir = mkdtempSync4(join7(tmpdir4(), "lisa-"));
1240
- const promptFile = join7(tmpDir, "prompt.md");
1241
- writeFileSync7(promptFile, prompt, "utf-8");
1320
+ const tmpDir = mkdtempSync5(join8(tmpdir5(), "lisa-"));
1321
+ const promptFile = join8(tmpDir, "prompt.md");
1322
+ writeFileSync8(promptFile, prompt, "utf-8");
1242
1323
  try {
1243
1324
  const modelFlag = opts.model ? `--model ${opts.model}` : "";
1244
- const proc = spawn4(
1325
+ const proc = spawn5(
1245
1326
  "sh",
1246
1327
  ["-c", `${bin} -p "$(cat '${promptFile}')" --output-format text --force ${modelFlag}`],
1247
1328
  {
@@ -1260,7 +1341,7 @@ var CursorProvider = class {
1260
1341
  }
1261
1342
  chunks.push(text2);
1262
1343
  try {
1263
- appendFileSync6(opts.logFile, text2);
1344
+ appendFileSync7(opts.logFile, text2);
1264
1345
  } catch {
1265
1346
  }
1266
1347
  });
@@ -1268,7 +1349,7 @@ var CursorProvider = class {
1268
1349
  const text2 = chunk.toString();
1269
1350
  if (getOutputMode() !== "tui") process.stderr.write(text2);
1270
1351
  try {
1271
- appendFileSync6(opts.logFile, text2);
1352
+ appendFileSync7(opts.logFile, text2);
1272
1353
  } catch {
1273
1354
  }
1274
1355
  });
@@ -1294,7 +1375,7 @@ var CursorProvider = class {
1294
1375
  };
1295
1376
  } finally {
1296
1377
  try {
1297
- unlinkSync4(promptFile);
1378
+ unlinkSync5(promptFile);
1298
1379
  } catch {
1299
1380
  }
1300
1381
  }
@@ -1302,15 +1383,15 @@ var CursorProvider = class {
1302
1383
  };
1303
1384
 
1304
1385
  // src/providers/gemini.ts
1305
- import { execSync as execSync5, spawn as spawn5 } from "child_process";
1306
- import { appendFileSync as appendFileSync7, mkdtempSync as mkdtempSync5, unlinkSync as unlinkSync5, writeFileSync as writeFileSync8 } from "fs";
1307
- import { tmpdir as tmpdir5 } from "os";
1308
- import { join as join8 } from "path";
1386
+ import { execSync as execSync6, spawn as spawn6 } from "child_process";
1387
+ import { appendFileSync as appendFileSync8, mkdtempSync as mkdtempSync6, unlinkSync as unlinkSync6, writeFileSync as writeFileSync9 } from "fs";
1388
+ import { tmpdir as tmpdir6 } from "os";
1389
+ import { join as join9 } from "path";
1309
1390
  var GeminiProvider = class {
1310
1391
  name = "gemini";
1311
1392
  async isAvailable() {
1312
1393
  try {
1313
- execSync5("gemini --version", { stdio: "ignore" });
1394
+ execSync6("gemini --version", { stdio: "ignore" });
1314
1395
  return true;
1315
1396
  } catch {
1316
1397
  return false;
@@ -1318,12 +1399,12 @@ var GeminiProvider = class {
1318
1399
  }
1319
1400
  async run(prompt, opts) {
1320
1401
  const start = Date.now();
1321
- const tmpDir = mkdtempSync5(join8(tmpdir5(), "lisa-"));
1322
- const promptFile = join8(tmpDir, "prompt.md");
1323
- writeFileSync8(promptFile, prompt, "utf-8");
1402
+ const tmpDir = mkdtempSync6(join9(tmpdir6(), "lisa-"));
1403
+ const promptFile = join9(tmpDir, "prompt.md");
1404
+ writeFileSync9(promptFile, prompt, "utf-8");
1324
1405
  try {
1325
1406
  const modelFlag = opts.model ? `--model ${opts.model}` : "";
1326
- const proc = spawn5("sh", ["-c", `gemini --yolo ${modelFlag} -p "$(cat '${promptFile}')"`], {
1407
+ const proc = spawn6("sh", ["-c", `gemini --yolo ${modelFlag} -p "$(cat '${promptFile}')"`], {
1327
1408
  cwd: opts.cwd,
1328
1409
  stdio: ["ignore", "pipe", "pipe"]
1329
1410
  });
@@ -1338,7 +1419,7 @@ var GeminiProvider = class {
1338
1419
  }
1339
1420
  chunks.push(text2);
1340
1421
  try {
1341
- appendFileSync7(opts.logFile, text2);
1422
+ appendFileSync8(opts.logFile, text2);
1342
1423
  } catch {
1343
1424
  }
1344
1425
  });
@@ -1346,7 +1427,7 @@ var GeminiProvider = class {
1346
1427
  const text2 = chunk.toString();
1347
1428
  if (getOutputMode() !== "tui") process.stderr.write(text2);
1348
1429
  try {
1349
- appendFileSync7(opts.logFile, text2);
1430
+ appendFileSync8(opts.logFile, text2);
1350
1431
  } catch {
1351
1432
  }
1352
1433
  });
@@ -1372,7 +1453,7 @@ var GeminiProvider = class {
1372
1453
  };
1373
1454
  } finally {
1374
1455
  try {
1375
- unlinkSync5(promptFile);
1456
+ unlinkSync6(promptFile);
1376
1457
  } catch {
1377
1458
  }
1378
1459
  }
@@ -1380,15 +1461,15 @@ var GeminiProvider = class {
1380
1461
  };
1381
1462
 
1382
1463
  // src/providers/goose.ts
1383
- import { execSync as execSync6, spawn as spawn6 } from "child_process";
1384
- import { appendFileSync as appendFileSync8, mkdtempSync as mkdtempSync6, unlinkSync as unlinkSync6, writeFileSync as writeFileSync9 } from "fs";
1385
- import { tmpdir as tmpdir6 } from "os";
1386
- import { join as join9 } from "path";
1464
+ import { execSync as execSync7, spawn as spawn7 } from "child_process";
1465
+ import { appendFileSync as appendFileSync9, mkdtempSync as mkdtempSync7, unlinkSync as unlinkSync7, writeFileSync as writeFileSync10 } from "fs";
1466
+ import { tmpdir as tmpdir7 } from "os";
1467
+ import { join as join10 } from "path";
1387
1468
  var GooseProvider = class {
1388
1469
  name = "goose";
1389
1470
  async isAvailable() {
1390
1471
  try {
1391
- execSync6("goose --version", { stdio: "ignore" });
1472
+ execSync7("goose --version", { stdio: "ignore" });
1392
1473
  return true;
1393
1474
  } catch {
1394
1475
  return false;
@@ -1396,12 +1477,12 @@ var GooseProvider = class {
1396
1477
  }
1397
1478
  async run(prompt, opts) {
1398
1479
  const start = Date.now();
1399
- const tmpDir = mkdtempSync6(join9(tmpdir6(), "lisa-"));
1400
- const promptFile = join9(tmpDir, "prompt.md");
1401
- writeFileSync9(promptFile, prompt, "utf-8");
1480
+ const tmpDir = mkdtempSync7(join10(tmpdir7(), "lisa-"));
1481
+ const promptFile = join10(tmpDir, "prompt.md");
1482
+ writeFileSync10(promptFile, prompt, "utf-8");
1402
1483
  try {
1403
1484
  const modelFlag = opts.model ? `--model ${opts.model}` : "";
1404
- const proc = spawn6("sh", ["-c", `goose run ${modelFlag} --text "$(cat '${promptFile}')"`], {
1485
+ const proc = spawn7("sh", ["-c", `goose run ${modelFlag} --text "$(cat '${promptFile}')"`], {
1405
1486
  cwd: opts.cwd,
1406
1487
  stdio: ["ignore", "pipe", "pipe"]
1407
1488
  });
@@ -1416,7 +1497,7 @@ var GooseProvider = class {
1416
1497
  }
1417
1498
  chunks.push(text2);
1418
1499
  try {
1419
- appendFileSync8(opts.logFile, text2);
1500
+ appendFileSync9(opts.logFile, text2);
1420
1501
  } catch {
1421
1502
  }
1422
1503
  });
@@ -1424,7 +1505,7 @@ var GooseProvider = class {
1424
1505
  const text2 = chunk.toString();
1425
1506
  if (getOutputMode() !== "tui") process.stderr.write(text2);
1426
1507
  try {
1427
- appendFileSync8(opts.logFile, text2);
1508
+ appendFileSync9(opts.logFile, text2);
1428
1509
  } catch {
1429
1510
  }
1430
1511
  });
@@ -1450,7 +1531,7 @@ var GooseProvider = class {
1450
1531
  };
1451
1532
  } finally {
1452
1533
  try {
1453
- unlinkSync6(promptFile);
1534
+ unlinkSync7(promptFile);
1454
1535
  } catch {
1455
1536
  }
1456
1537
  }
@@ -1458,15 +1539,15 @@ var GooseProvider = class {
1458
1539
  };
1459
1540
 
1460
1541
  // src/providers/opencode.ts
1461
- import { execSync as execSync7, spawn as spawn7 } from "child_process";
1462
- import { appendFileSync as appendFileSync9, mkdtempSync as mkdtempSync7, unlinkSync as unlinkSync7, writeFileSync as writeFileSync10 } from "fs";
1463
- import { tmpdir as tmpdir7 } from "os";
1464
- import { join as join10 } from "path";
1542
+ import { execSync as execSync8, spawn as spawn8 } from "child_process";
1543
+ import { appendFileSync as appendFileSync10, mkdtempSync as mkdtempSync8, unlinkSync as unlinkSync8, writeFileSync as writeFileSync11 } from "fs";
1544
+ import { tmpdir as tmpdir8 } from "os";
1545
+ import { join as join11 } from "path";
1465
1546
  var OpenCodeProvider = class {
1466
1547
  name = "opencode";
1467
1548
  async isAvailable() {
1468
1549
  try {
1469
- execSync7("opencode --version", { stdio: "ignore" });
1550
+ execSync8("opencode --version", { stdio: "ignore" });
1470
1551
  return true;
1471
1552
  } catch {
1472
1553
  return false;
@@ -1474,11 +1555,11 @@ var OpenCodeProvider = class {
1474
1555
  }
1475
1556
  async run(prompt, opts) {
1476
1557
  const start = Date.now();
1477
- const tmpDir = mkdtempSync7(join10(tmpdir7(), "lisa-"));
1478
- const promptFile = join10(tmpDir, "prompt.md");
1479
- writeFileSync10(promptFile, prompt, "utf-8");
1558
+ const tmpDir = mkdtempSync8(join11(tmpdir8(), "lisa-"));
1559
+ const promptFile = join11(tmpDir, "prompt.md");
1560
+ writeFileSync11(promptFile, prompt, "utf-8");
1480
1561
  try {
1481
- const proc = spawn7("sh", ["-c", `opencode run "$(cat '${promptFile}')"`], {
1562
+ const proc = spawn8("sh", ["-c", `opencode run "$(cat '${promptFile}')"`], {
1482
1563
  cwd: opts.cwd,
1483
1564
  stdio: ["ignore", "pipe", "pipe"]
1484
1565
  });
@@ -1493,7 +1574,7 @@ var OpenCodeProvider = class {
1493
1574
  }
1494
1575
  chunks.push(text2);
1495
1576
  try {
1496
- appendFileSync9(opts.logFile, text2);
1577
+ appendFileSync10(opts.logFile, text2);
1497
1578
  } catch {
1498
1579
  }
1499
1580
  });
@@ -1501,7 +1582,7 @@ var OpenCodeProvider = class {
1501
1582
  const text2 = chunk.toString();
1502
1583
  if (getOutputMode() !== "tui") process.stderr.write(text2);
1503
1584
  try {
1504
- appendFileSync9(opts.logFile, text2);
1585
+ appendFileSync10(opts.logFile, text2);
1505
1586
  } catch {
1506
1587
  }
1507
1588
  });
@@ -1527,7 +1608,7 @@ var OpenCodeProvider = class {
1527
1608
  };
1528
1609
  } finally {
1529
1610
  try {
1530
- unlinkSync7(promptFile);
1611
+ unlinkSync8(promptFile);
1531
1612
  } catch {
1532
1613
  }
1533
1614
  }
@@ -1542,7 +1623,8 @@ var providers = {
1542
1623
  copilot: () => new CopilotProvider(),
1543
1624
  cursor: () => new CursorProvider(),
1544
1625
  goose: () => new GooseProvider(),
1545
- aider: () => new AiderProvider()
1626
+ aider: () => new AiderProvider(),
1627
+ codex: () => new CodexProvider()
1546
1628
  };
1547
1629
  async function getAllProvidersWithAvailability() {
1548
1630
  const all = Object.values(providers).map((f) => f());
@@ -1671,7 +1753,7 @@ function formatAttemptsReport(attempts) {
1671
1753
  }
1672
1754
 
1673
1755
  // src/session/lifecycle.ts
1674
- import { spawn as spawn8 } from "child_process";
1756
+ import { spawn as spawn9 } from "child_process";
1675
1757
  import { createConnection } from "net";
1676
1758
  import { resolve as resolve4 } from "path";
1677
1759
  var managedResources = [];
@@ -1709,7 +1791,7 @@ function waitForPort(port, timeoutMs) {
1709
1791
  }
1710
1792
  function spawnResource(config2, baseCwd) {
1711
1793
  const cwd = config2.cwd ? resolve4(baseCwd, config2.cwd) : baseCwd;
1712
- const child = spawn8("sh", ["-c", config2.up], {
1794
+ const child = spawn9("sh", ["-c", config2.up], {
1713
1795
  cwd,
1714
1796
  stdio: "ignore",
1715
1797
  detached: true
@@ -1719,7 +1801,7 @@ function spawnResource(config2, baseCwd) {
1719
1801
  }
1720
1802
  function runSetupCommand(command, cwd) {
1721
1803
  return new Promise((resolve6, reject) => {
1722
- const child = spawn8("sh", ["-c", command], {
1804
+ const child = spawn9("sh", ["-c", command], {
1723
1805
  cwd,
1724
1806
  stdio: "inherit"
1725
1807
  });
@@ -1790,7 +1872,7 @@ async function stopResources() {
1790
1872
  }
1791
1873
  } else {
1792
1874
  await new Promise((resolve6) => {
1793
- const down = spawn8("sh", ["-c", config2.down], {
1875
+ const down = spawn9("sh", ["-c", config2.down], {
1794
1876
  stdio: "ignore"
1795
1877
  });
1796
1878
  down.on("close", () => resolve6());
@@ -3154,11 +3236,27 @@ function createSource(name) {
3154
3236
  var activeCleanup = null;
3155
3237
  var activeProviderPid = null;
3156
3238
  var shuttingDown = false;
3239
+ var loopPaused = false;
3240
+ kanbanEmitter.on("loop:pause", () => {
3241
+ loopPaused = true;
3242
+ });
3243
+ kanbanEmitter.on("loop:resume", () => {
3244
+ loopPaused = false;
3245
+ });
3157
3246
  function resolveModels(config2) {
3158
3247
  if (!config2.models || config2.models.length === 0) {
3159
3248
  return [{ provider: config2.provider }];
3160
3249
  }
3161
- const knownProviders = /* @__PURE__ */ new Set(["claude", "gemini", "opencode", "copilot", "cursor"]);
3250
+ const knownProviders = /* @__PURE__ */ new Set([
3251
+ "claude",
3252
+ "gemini",
3253
+ "opencode",
3254
+ "copilot",
3255
+ "cursor",
3256
+ "goose",
3257
+ "aider",
3258
+ "codex"
3259
+ ]);
3162
3260
  for (const m of config2.models) {
3163
3261
  if (knownProviders.has(m) && m !== config2.provider) {
3164
3262
  warn(
@@ -3182,7 +3280,7 @@ function resolveModels(config2) {
3182
3280
  }
3183
3281
  var PLAN_FILE = ".lisa-plan.json";
3184
3282
  function readLisaPlan(dir) {
3185
- const planPath = join11(dir, PLAN_FILE);
3283
+ const planPath = join12(dir, PLAN_FILE);
3186
3284
  if (!existsSync6(planPath)) return null;
3187
3285
  try {
3188
3286
  return JSON.parse(readFileSync5(planPath, "utf-8").trim());
@@ -3192,13 +3290,13 @@ function readLisaPlan(dir) {
3192
3290
  }
3193
3291
  function cleanupPlan(dir) {
3194
3292
  try {
3195
- unlinkSync8(join11(dir, PLAN_FILE));
3293
+ unlinkSync9(join12(dir, PLAN_FILE));
3196
3294
  } catch {
3197
3295
  }
3198
3296
  }
3199
3297
  var MANIFEST_FILE = ".lisa-manifest.json";
3200
3298
  function readLisaManifest(dir) {
3201
- const manifestPath = join11(dir, MANIFEST_FILE);
3299
+ const manifestPath = join12(dir, MANIFEST_FILE);
3202
3300
  if (!existsSync6(manifestPath)) return null;
3203
3301
  try {
3204
3302
  return JSON.parse(readFileSync5(manifestPath, "utf-8").trim());
@@ -3208,7 +3306,7 @@ function readLisaManifest(dir) {
3208
3306
  }
3209
3307
  function cleanupManifest(dir) {
3210
3308
  try {
3211
- unlinkSync8(join11(dir, MANIFEST_FILE));
3309
+ unlinkSync9(join12(dir, MANIFEST_FILE));
3212
3310
  } catch {
3213
3311
  }
3214
3312
  }
@@ -3320,6 +3418,7 @@ async function runLoop(config2, opts) {
3320
3418
  const timestamp2 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").substring(0, 19);
3321
3419
  const logFile = resolve5(config2.logs.dir, `session_${session}_${timestamp2}.log`);
3322
3420
  divider(session);
3421
+ await waitIfPaused();
3323
3422
  startSpinner("fetching issue...");
3324
3423
  if (opts.issueId) {
3325
3424
  log(`Fetching issue '${opts.issueId}' from ${config2.source}...`);
@@ -3600,7 +3699,7 @@ async function runNativeWorktreeSession(config2, issue2, logFile, session, model
3600
3699
  });
3601
3700
  stopSpinner();
3602
3701
  try {
3603
- appendFileSync10(
3702
+ appendFileSync11(
3604
3703
  logFile,
3605
3704
  `
3606
3705
  ${"=".repeat(80)}
@@ -3707,7 +3806,7 @@ async function runManualWorktreeSession(config2, issue2, logFile, session, model
3707
3806
  });
3708
3807
  stopSpinner();
3709
3808
  try {
3710
- appendFileSync10(
3809
+ appendFileSync11(
3711
3810
  logFile,
3712
3811
  `
3713
3812
  ${"=".repeat(80)}
@@ -3766,7 +3865,7 @@ async function runWorktreeMultiRepoSession(config2, issue2, logFile, session, mo
3766
3865
  });
3767
3866
  stopSpinner();
3768
3867
  try {
3769
- appendFileSync10(
3868
+ appendFileSync11(
3770
3869
  logFile,
3771
3870
  `
3772
3871
  ${"=".repeat(80)}
@@ -3902,7 +4001,7 @@ async function runMultiRepoStep(config2, issue2, step, previousResults, logFile,
3902
4001
  stopSpinner();
3903
4002
  if (repoConfig?.lifecycle) await stopResources();
3904
4003
  try {
3905
- appendFileSync10(
4004
+ appendFileSync11(
3906
4005
  logFile,
3907
4006
  `
3908
4007
  ${"=".repeat(80)}
@@ -3981,7 +4080,7 @@ async function runBranchSession(config2, issue2, logFile, session, models) {
3981
4080
  });
3982
4081
  stopSpinner();
3983
4082
  try {
3984
- appendFileSync10(
4083
+ appendFileSync11(
3985
4084
  logFile,
3986
4085
  `
3987
4086
  ${"=".repeat(80)}
@@ -4026,6 +4125,11 @@ async function cleanupWorktree(repoRoot, worktreePath) {
4026
4125
  function sleep(ms) {
4027
4126
  return new Promise((resolve6) => setTimeout(resolve6, ms));
4028
4127
  }
4128
+ async function waitIfPaused() {
4129
+ while (loopPaused) {
4130
+ await sleep(500);
4131
+ }
4132
+ }
4029
4133
 
4030
4134
  // src/cli.ts
4031
4135
  function sleep2(ms) {
@@ -4082,7 +4186,7 @@ Add them to your ${shell} and run: source ${shell}`));
4082
4186
  if (isTUI) {
4083
4187
  const { render } = await import("ink");
4084
4188
  const { createElement } = await import("react");
4085
- const { KanbanApp } = await import("./kanban-YP3TJJUT.js");
4189
+ const { KanbanApp } = await import("./kanban-5C3WZIKC.js");
4086
4190
  render(createElement(KanbanApp, { config: merged }), { exitOnCtrlC: false });
4087
4191
  }
4088
4192
  await runLoop(merged, {
@@ -4182,21 +4286,21 @@ function getVersion() {
4182
4286
  }
4183
4287
  var CURSOR_FREE_PLAN_ERROR = "Free plans can only use Auto";
4184
4288
  async function isCursorFreePlan() {
4185
- const { mkdtempSync: mkdtempSync8, unlinkSync: unlinkSync9, writeFileSync: writeFileSync11 } = await import("fs");
4186
- const tmpDir = mkdtempSync8(join12(tmpdir8(), "lisa-cursor-check-"));
4187
- const promptFile = join12(tmpDir, "prompt.txt");
4188
- writeFileSync11(promptFile, "test", "utf-8");
4289
+ const { mkdtempSync: mkdtempSync9, unlinkSync: unlinkSync10, writeFileSync: writeFileSync12 } = await import("fs");
4290
+ const tmpDir = mkdtempSync9(join13(tmpdir9(), "lisa-cursor-check-"));
4291
+ const promptFile = join13(tmpDir, "prompt.txt");
4292
+ writeFileSync12(promptFile, "test", "utf-8");
4189
4293
  try {
4190
4294
  const bin = ["agent", "cursor-agent"].find((b) => {
4191
4295
  try {
4192
- execSync8(`${b} --version`, { stdio: "ignore" });
4296
+ execSync9(`${b} --version`, { stdio: "ignore" });
4193
4297
  return true;
4194
4298
  } catch {
4195
4299
  return false;
4196
4300
  }
4197
4301
  });
4198
4302
  if (!bin) return false;
4199
- const output = execSync8(`${bin} -p "$(cat '${promptFile}')" --output-format text`, {
4303
+ const output = execSync9(`${bin} -p "$(cat '${promptFile}')" --output-format text`, {
4200
4304
  cwd: process.cwd(),
4201
4305
  encoding: "utf-8",
4202
4306
  timeout: 3e4
@@ -4207,11 +4311,11 @@ async function isCursorFreePlan() {
4207
4311
  return errorOutput.includes(CURSOR_FREE_PLAN_ERROR);
4208
4312
  } finally {
4209
4313
  try {
4210
- unlinkSync9(promptFile);
4314
+ unlinkSync10(promptFile);
4211
4315
  } catch {
4212
4316
  }
4213
4317
  try {
4214
- execSync8(`rm -rf ${tmpDir}`, { stdio: "ignore" });
4318
+ execSync9(`rm -rf ${tmpDir}`, { stdio: "ignore" });
4215
4319
  } catch {
4216
4320
  }
4217
4321
  }
@@ -4278,38 +4382,45 @@ var issue = defineCommand({
4278
4382
  meta: { name: "issue", description: "Issue tracker operations for use inside worktrees" },
4279
4383
  subCommands: { get: issueGet, done: issueDone }
4280
4384
  });
4281
- var CURSOR_MODELS_FALLBACK = [
4385
+ var CURSOR_PREFERRED_MODELS = [
4282
4386
  "auto",
4283
4387
  "composer-1.5",
4388
+ "composer-1",
4389
+ "gpt-5.3-codex",
4390
+ "gpt-5.2",
4391
+ "gpt-5.1-codex-max",
4284
4392
  "opus-4.6-thinking",
4285
4393
  "opus-4.6",
4394
+ "sonnet-4.6-thinking",
4286
4395
  "sonnet-4.6",
4287
- "gpt-5.3-codex",
4288
- "gpt-5.2",
4289
- "gemini-3.1-pro"
4396
+ "gemini-3.1-pro",
4397
+ "gemini-3-pro",
4398
+ "grok",
4399
+ "kimi-k2.5"
4290
4400
  ];
4291
4401
  function fetchCursorModels() {
4292
4402
  try {
4293
4403
  const bin = ["agent", "cursor-agent"].find((b) => {
4294
4404
  try {
4295
- execSync8(`${b} --version`, { stdio: "ignore" });
4405
+ execSync9(`${b} --version`, { stdio: "ignore" });
4296
4406
  return true;
4297
4407
  } catch {
4298
4408
  return false;
4299
4409
  }
4300
4410
  });
4301
- if (!bin) return CURSOR_MODELS_FALLBACK;
4302
- const raw = execSync8(`${bin} --list-models`, { encoding: "utf-8", timeout: 1e4 });
4411
+ if (!bin) return CURSOR_PREFERRED_MODELS;
4412
+ const raw = execSync9(`${bin} --list-models`, { encoding: "utf-8", timeout: 1e4 });
4303
4413
  const clean = raw.replace(/\x1b\[[0-9;]*[mGKHFA-Z]/g, "");
4304
- const models = clean.split("\n").map((l) => l.trim()).filter((l) => l.includes(" - ")).map((l) => (l.split(" - ")[0] ?? "").trim()).filter(Boolean);
4305
- return models.length > 0 ? models : CURSOR_MODELS_FALLBACK;
4414
+ const all = clean.split("\n").map((l) => l.trim()).filter((l) => l.includes(" - ")).map((l) => (l.split(" - ")[0] ?? "").trim()).filter(Boolean);
4415
+ const filtered = CURSOR_PREFERRED_MODELS.filter((m) => all.includes(m));
4416
+ return filtered.length > 0 ? filtered : CURSOR_PREFERRED_MODELS;
4306
4417
  } catch {
4307
- return CURSOR_MODELS_FALLBACK;
4418
+ return CURSOR_PREFERRED_MODELS;
4308
4419
  }
4309
4420
  }
4310
4421
  function fetchOpenCodeModels() {
4311
4422
  try {
4312
- const raw = execSync8("opencode models", { encoding: "utf-8", timeout: 1e4 });
4423
+ const raw = execSync9("opencode models", { encoding: "utf-8", timeout: 1e4 });
4313
4424
  const hasAnthropic = Boolean(process.env.ANTHROPIC_API_KEY);
4314
4425
  const hasGoogle = Boolean(
4315
4426
  process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY || process.env.GOOGLE_GENERATIVE_AI_API_KEY
@@ -4353,7 +4464,8 @@ async function runConfigWizard(existing) {
4353
4464
  copilot: "GitHub Copilot CLI",
4354
4465
  cursor: "Cursor Agent",
4355
4466
  goose: "Goose",
4356
- aider: "Aider"
4467
+ aider: "Aider",
4468
+ codex: "OpenAI Codex"
4357
4469
  };
4358
4470
  const providerModels = {
4359
4471
  claude: ["claude-opus-4-6", "claude-sonnet-4-6", "claude-haiku-4-5", "claude-sonnet-4-5"],
@@ -4361,7 +4473,8 @@ async function runConfigWizard(existing) {
4361
4473
  // opencode: populated dynamically below (fetchOpenCodeModels)
4362
4474
  copilot: ["claude-opus-4.6", "claude-sonnet-4.6", "claude-haiku-4.5", "gpt-5.2"],
4363
4475
  goose: ["claude-sonnet-4-5", "claude-opus-4-5", "claude-haiku-4-5"],
4364
- aider: ["claude-opus-4-6", "claude-sonnet-4-5", "claude-haiku-4-5"]
4476
+ aider: ["claude-opus-4-6", "claude-sonnet-4-5", "claude-haiku-4-5"],
4477
+ codex: ["gpt-5.1-codex-mini", "gpt-5.1-codex-max", "gpt-5.2-codex", "gpt-5.2", "gpt-5.3-codex"]
4365
4478
  // cursor: populated dynamically below (fetchCursorModels)
4366
4479
  };
4367
4480
  const allProviders = await getAllProvidersWithAvailability();
@@ -4375,6 +4488,7 @@ async function runConfigWizard(existing) {
4375
4488
  ${pc2.bold("Gemini CLI")} ${pc2.dim("npm i -g @google/gemini-cli")}
4376
4489
  ${pc2.bold("OpenCode")} ${pc2.dim("npm i -g opencode")}
4377
4490
  ${pc2.bold("GitHub Copilot CLI")} ${pc2.dim("npm i -g @github/copilot-cli")}
4491
+ ${pc2.bold("OpenAI Codex")} ${pc2.dim("npm i -g @openai/codex")}
4378
4492
  ${pc2.bold("Goose")} ${pc2.dim("https://block.github.io/goose")}
4379
4493
  ${pc2.bold("Aider")} ${pc2.dim("pip install aider-chat")}`
4380
4494
  );
@@ -4662,12 +4776,12 @@ async function detectGitHubMethod() {
4662
4776
  }
4663
4777
  async function detectGitRepos() {
4664
4778
  const cwd = process.cwd();
4665
- if (existsSync7(join12(cwd, ".git"))) {
4779
+ if (existsSync7(join13(cwd, ".git"))) {
4666
4780
  clack.log.info("Found a git repository in the current directory.");
4667
4781
  return [];
4668
4782
  }
4669
4783
  const entries = readdirSync(cwd, { withFileTypes: true });
4670
- const gitDirs = entries.filter((e) => e.isDirectory() && existsSync7(join12(cwd, e.name, ".git"))).map((e) => e.name);
4784
+ const gitDirs = entries.filter((e) => e.isDirectory() && existsSync7(join13(cwd, e.name, ".git"))).map((e) => e.name);
4671
4785
  if (gitDirs.length === 0) {
4672
4786
  return [];
4673
4787
  }
@@ -4677,7 +4791,7 @@ async function detectGitRepos() {
4677
4791
  });
4678
4792
  if (clack.isCancel(selected)) return process.exit(0);
4679
4793
  return selected.map((dir) => ({
4680
- name: getGitRepoName(join12(cwd, dir)) ?? dir,
4794
+ name: getGitRepoName(join13(cwd, dir)) ?? dir,
4681
4795
  path: `./${dir}`,
4682
4796
  match: "",
4683
4797
  base_branch: ""
@@ -4685,7 +4799,7 @@ async function detectGitRepos() {
4685
4799
  }
4686
4800
  function detectDefaultBranch(repoPath) {
4687
4801
  try {
4688
- const ref = execSync8("git symbolic-ref refs/remotes/origin/HEAD --short", {
4802
+ const ref = execSync9("git symbolic-ref refs/remotes/origin/HEAD --short", {
4689
4803
  cwd: repoPath,
4690
4804
  encoding: "utf-8"
4691
4805
  }).trim();
@@ -4696,7 +4810,7 @@ function detectDefaultBranch(repoPath) {
4696
4810
  }
4697
4811
  function getGitRepoName(repoPath) {
4698
4812
  try {
4699
- const url = execSync8("git remote get-url origin", { cwd: repoPath, encoding: "utf-8" }).trim();
4813
+ const url = execSync9("git remote get-url origin", { cwd: repoPath, encoding: "utf-8" }).trim();
4700
4814
  const match = url.match(/\/([^/]+?)(?:\.git)?$/) ?? url.match(/:([^/]+?)(?:\.git)?$/);
4701
4815
  return match?.[1] ?? null;
4702
4816
  } catch {
@@ -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(Sidebar, { provider: config.provider, source: config.source, cwd: process.cwd() }),
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
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tarcisiopgs/lisa",
3
- "version": "1.7.6",
3
+ "version": "1.8.0",
4
4
  "description": "Autonomous issue resolver",
5
5
  "license": "MIT",
6
6
  "type": "module",