@tarcisiopgs/lisa 1.7.7 → 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 +1 -0
- package/dist/index.js +184 -90
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -82,6 +82,7 @@ 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
|
|
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
|
|
12
|
+
import { execSync as execSync9 } from "child_process";
|
|
13
13
|
import { existsSync as existsSync7, readdirSync, readFileSync as readFileSync6 } from "fs";
|
|
14
|
-
import { tmpdir as
|
|
15
|
-
import { join as
|
|
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
|
|
285
|
-
import { join as
|
|
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/
|
|
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
|
|
1138
|
-
name = "
|
|
1138
|
+
var CodexProvider = class {
|
|
1139
|
+
name = "codex";
|
|
1139
1140
|
async isAvailable() {
|
|
1140
1141
|
try {
|
|
1141
|
-
execSync3("
|
|
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
|
|
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/
|
|
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
|
-
|
|
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 =
|
|
1240
|
-
const promptFile =
|
|
1241
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
1306
|
-
import { appendFileSync as
|
|
1307
|
-
import { tmpdir as
|
|
1308
|
-
import { join as
|
|
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
|
-
|
|
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 =
|
|
1322
|
-
const promptFile =
|
|
1323
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
1384
|
-
import { appendFileSync as
|
|
1385
|
-
import { tmpdir as
|
|
1386
|
-
import { join as
|
|
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
|
-
|
|
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 =
|
|
1400
|
-
const promptFile =
|
|
1401
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
1462
|
-
import { appendFileSync as
|
|
1463
|
-
import { tmpdir as
|
|
1464
|
-
import { join as
|
|
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
|
-
|
|
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 =
|
|
1478
|
-
const promptFile =
|
|
1479
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
1875
|
+
const down = spawn9("sh", ["-c", config2.down], {
|
|
1794
1876
|
stdio: "ignore"
|
|
1795
1877
|
});
|
|
1796
1878
|
down.on("close", () => resolve6());
|
|
@@ -3165,7 +3247,16 @@ function resolveModels(config2) {
|
|
|
3165
3247
|
if (!config2.models || config2.models.length === 0) {
|
|
3166
3248
|
return [{ provider: config2.provider }];
|
|
3167
3249
|
}
|
|
3168
|
-
const knownProviders = /* @__PURE__ */ new Set([
|
|
3250
|
+
const knownProviders = /* @__PURE__ */ new Set([
|
|
3251
|
+
"claude",
|
|
3252
|
+
"gemini",
|
|
3253
|
+
"opencode",
|
|
3254
|
+
"copilot",
|
|
3255
|
+
"cursor",
|
|
3256
|
+
"goose",
|
|
3257
|
+
"aider",
|
|
3258
|
+
"codex"
|
|
3259
|
+
]);
|
|
3169
3260
|
for (const m of config2.models) {
|
|
3170
3261
|
if (knownProviders.has(m) && m !== config2.provider) {
|
|
3171
3262
|
warn(
|
|
@@ -3189,7 +3280,7 @@ function resolveModels(config2) {
|
|
|
3189
3280
|
}
|
|
3190
3281
|
var PLAN_FILE = ".lisa-plan.json";
|
|
3191
3282
|
function readLisaPlan(dir) {
|
|
3192
|
-
const planPath =
|
|
3283
|
+
const planPath = join12(dir, PLAN_FILE);
|
|
3193
3284
|
if (!existsSync6(planPath)) return null;
|
|
3194
3285
|
try {
|
|
3195
3286
|
return JSON.parse(readFileSync5(planPath, "utf-8").trim());
|
|
@@ -3199,13 +3290,13 @@ function readLisaPlan(dir) {
|
|
|
3199
3290
|
}
|
|
3200
3291
|
function cleanupPlan(dir) {
|
|
3201
3292
|
try {
|
|
3202
|
-
|
|
3293
|
+
unlinkSync9(join12(dir, PLAN_FILE));
|
|
3203
3294
|
} catch {
|
|
3204
3295
|
}
|
|
3205
3296
|
}
|
|
3206
3297
|
var MANIFEST_FILE = ".lisa-manifest.json";
|
|
3207
3298
|
function readLisaManifest(dir) {
|
|
3208
|
-
const manifestPath =
|
|
3299
|
+
const manifestPath = join12(dir, MANIFEST_FILE);
|
|
3209
3300
|
if (!existsSync6(manifestPath)) return null;
|
|
3210
3301
|
try {
|
|
3211
3302
|
return JSON.parse(readFileSync5(manifestPath, "utf-8").trim());
|
|
@@ -3215,7 +3306,7 @@ function readLisaManifest(dir) {
|
|
|
3215
3306
|
}
|
|
3216
3307
|
function cleanupManifest(dir) {
|
|
3217
3308
|
try {
|
|
3218
|
-
|
|
3309
|
+
unlinkSync9(join12(dir, MANIFEST_FILE));
|
|
3219
3310
|
} catch {
|
|
3220
3311
|
}
|
|
3221
3312
|
}
|
|
@@ -3608,7 +3699,7 @@ async function runNativeWorktreeSession(config2, issue2, logFile, session, model
|
|
|
3608
3699
|
});
|
|
3609
3700
|
stopSpinner();
|
|
3610
3701
|
try {
|
|
3611
|
-
|
|
3702
|
+
appendFileSync11(
|
|
3612
3703
|
logFile,
|
|
3613
3704
|
`
|
|
3614
3705
|
${"=".repeat(80)}
|
|
@@ -3715,7 +3806,7 @@ async function runManualWorktreeSession(config2, issue2, logFile, session, model
|
|
|
3715
3806
|
});
|
|
3716
3807
|
stopSpinner();
|
|
3717
3808
|
try {
|
|
3718
|
-
|
|
3809
|
+
appendFileSync11(
|
|
3719
3810
|
logFile,
|
|
3720
3811
|
`
|
|
3721
3812
|
${"=".repeat(80)}
|
|
@@ -3774,7 +3865,7 @@ async function runWorktreeMultiRepoSession(config2, issue2, logFile, session, mo
|
|
|
3774
3865
|
});
|
|
3775
3866
|
stopSpinner();
|
|
3776
3867
|
try {
|
|
3777
|
-
|
|
3868
|
+
appendFileSync11(
|
|
3778
3869
|
logFile,
|
|
3779
3870
|
`
|
|
3780
3871
|
${"=".repeat(80)}
|
|
@@ -3910,7 +4001,7 @@ async function runMultiRepoStep(config2, issue2, step, previousResults, logFile,
|
|
|
3910
4001
|
stopSpinner();
|
|
3911
4002
|
if (repoConfig?.lifecycle) await stopResources();
|
|
3912
4003
|
try {
|
|
3913
|
-
|
|
4004
|
+
appendFileSync11(
|
|
3914
4005
|
logFile,
|
|
3915
4006
|
`
|
|
3916
4007
|
${"=".repeat(80)}
|
|
@@ -3989,7 +4080,7 @@ async function runBranchSession(config2, issue2, logFile, session, models) {
|
|
|
3989
4080
|
});
|
|
3990
4081
|
stopSpinner();
|
|
3991
4082
|
try {
|
|
3992
|
-
|
|
4083
|
+
appendFileSync11(
|
|
3993
4084
|
logFile,
|
|
3994
4085
|
`
|
|
3995
4086
|
${"=".repeat(80)}
|
|
@@ -4195,21 +4286,21 @@ function getVersion() {
|
|
|
4195
4286
|
}
|
|
4196
4287
|
var CURSOR_FREE_PLAN_ERROR = "Free plans can only use Auto";
|
|
4197
4288
|
async function isCursorFreePlan() {
|
|
4198
|
-
const { mkdtempSync:
|
|
4199
|
-
const tmpDir =
|
|
4200
|
-
const promptFile =
|
|
4201
|
-
|
|
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");
|
|
4202
4293
|
try {
|
|
4203
4294
|
const bin = ["agent", "cursor-agent"].find((b) => {
|
|
4204
4295
|
try {
|
|
4205
|
-
|
|
4296
|
+
execSync9(`${b} --version`, { stdio: "ignore" });
|
|
4206
4297
|
return true;
|
|
4207
4298
|
} catch {
|
|
4208
4299
|
return false;
|
|
4209
4300
|
}
|
|
4210
4301
|
});
|
|
4211
4302
|
if (!bin) return false;
|
|
4212
|
-
const output =
|
|
4303
|
+
const output = execSync9(`${bin} -p "$(cat '${promptFile}')" --output-format text`, {
|
|
4213
4304
|
cwd: process.cwd(),
|
|
4214
4305
|
encoding: "utf-8",
|
|
4215
4306
|
timeout: 3e4
|
|
@@ -4220,11 +4311,11 @@ async function isCursorFreePlan() {
|
|
|
4220
4311
|
return errorOutput.includes(CURSOR_FREE_PLAN_ERROR);
|
|
4221
4312
|
} finally {
|
|
4222
4313
|
try {
|
|
4223
|
-
|
|
4314
|
+
unlinkSync10(promptFile);
|
|
4224
4315
|
} catch {
|
|
4225
4316
|
}
|
|
4226
4317
|
try {
|
|
4227
|
-
|
|
4318
|
+
execSync9(`rm -rf ${tmpDir}`, { stdio: "ignore" });
|
|
4228
4319
|
} catch {
|
|
4229
4320
|
}
|
|
4230
4321
|
}
|
|
@@ -4311,14 +4402,14 @@ function fetchCursorModels() {
|
|
|
4311
4402
|
try {
|
|
4312
4403
|
const bin = ["agent", "cursor-agent"].find((b) => {
|
|
4313
4404
|
try {
|
|
4314
|
-
|
|
4405
|
+
execSync9(`${b} --version`, { stdio: "ignore" });
|
|
4315
4406
|
return true;
|
|
4316
4407
|
} catch {
|
|
4317
4408
|
return false;
|
|
4318
4409
|
}
|
|
4319
4410
|
});
|
|
4320
4411
|
if (!bin) return CURSOR_PREFERRED_MODELS;
|
|
4321
|
-
const raw =
|
|
4412
|
+
const raw = execSync9(`${bin} --list-models`, { encoding: "utf-8", timeout: 1e4 });
|
|
4322
4413
|
const clean = raw.replace(/\x1b\[[0-9;]*[mGKHFA-Z]/g, "");
|
|
4323
4414
|
const all = clean.split("\n").map((l) => l.trim()).filter((l) => l.includes(" - ")).map((l) => (l.split(" - ")[0] ?? "").trim()).filter(Boolean);
|
|
4324
4415
|
const filtered = CURSOR_PREFERRED_MODELS.filter((m) => all.includes(m));
|
|
@@ -4329,7 +4420,7 @@ function fetchCursorModels() {
|
|
|
4329
4420
|
}
|
|
4330
4421
|
function fetchOpenCodeModels() {
|
|
4331
4422
|
try {
|
|
4332
|
-
const raw =
|
|
4423
|
+
const raw = execSync9("opencode models", { encoding: "utf-8", timeout: 1e4 });
|
|
4333
4424
|
const hasAnthropic = Boolean(process.env.ANTHROPIC_API_KEY);
|
|
4334
4425
|
const hasGoogle = Boolean(
|
|
4335
4426
|
process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY || process.env.GOOGLE_GENERATIVE_AI_API_KEY
|
|
@@ -4373,7 +4464,8 @@ async function runConfigWizard(existing) {
|
|
|
4373
4464
|
copilot: "GitHub Copilot CLI",
|
|
4374
4465
|
cursor: "Cursor Agent",
|
|
4375
4466
|
goose: "Goose",
|
|
4376
|
-
aider: "Aider"
|
|
4467
|
+
aider: "Aider",
|
|
4468
|
+
codex: "OpenAI Codex"
|
|
4377
4469
|
};
|
|
4378
4470
|
const providerModels = {
|
|
4379
4471
|
claude: ["claude-opus-4-6", "claude-sonnet-4-6", "claude-haiku-4-5", "claude-sonnet-4-5"],
|
|
@@ -4381,7 +4473,8 @@ async function runConfigWizard(existing) {
|
|
|
4381
4473
|
// opencode: populated dynamically below (fetchOpenCodeModels)
|
|
4382
4474
|
copilot: ["claude-opus-4.6", "claude-sonnet-4.6", "claude-haiku-4.5", "gpt-5.2"],
|
|
4383
4475
|
goose: ["claude-sonnet-4-5", "claude-opus-4-5", "claude-haiku-4-5"],
|
|
4384
|
-
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"]
|
|
4385
4478
|
// cursor: populated dynamically below (fetchCursorModels)
|
|
4386
4479
|
};
|
|
4387
4480
|
const allProviders = await getAllProvidersWithAvailability();
|
|
@@ -4395,6 +4488,7 @@ async function runConfigWizard(existing) {
|
|
|
4395
4488
|
${pc2.bold("Gemini CLI")} ${pc2.dim("npm i -g @google/gemini-cli")}
|
|
4396
4489
|
${pc2.bold("OpenCode")} ${pc2.dim("npm i -g opencode")}
|
|
4397
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")}
|
|
4398
4492
|
${pc2.bold("Goose")} ${pc2.dim("https://block.github.io/goose")}
|
|
4399
4493
|
${pc2.bold("Aider")} ${pc2.dim("pip install aider-chat")}`
|
|
4400
4494
|
);
|
|
@@ -4682,12 +4776,12 @@ async function detectGitHubMethod() {
|
|
|
4682
4776
|
}
|
|
4683
4777
|
async function detectGitRepos() {
|
|
4684
4778
|
const cwd = process.cwd();
|
|
4685
|
-
if (existsSync7(
|
|
4779
|
+
if (existsSync7(join13(cwd, ".git"))) {
|
|
4686
4780
|
clack.log.info("Found a git repository in the current directory.");
|
|
4687
4781
|
return [];
|
|
4688
4782
|
}
|
|
4689
4783
|
const entries = readdirSync(cwd, { withFileTypes: true });
|
|
4690
|
-
const gitDirs = entries.filter((e) => e.isDirectory() && existsSync7(
|
|
4784
|
+
const gitDirs = entries.filter((e) => e.isDirectory() && existsSync7(join13(cwd, e.name, ".git"))).map((e) => e.name);
|
|
4691
4785
|
if (gitDirs.length === 0) {
|
|
4692
4786
|
return [];
|
|
4693
4787
|
}
|
|
@@ -4697,7 +4791,7 @@ async function detectGitRepos() {
|
|
|
4697
4791
|
});
|
|
4698
4792
|
if (clack.isCancel(selected)) return process.exit(0);
|
|
4699
4793
|
return selected.map((dir) => ({
|
|
4700
|
-
name: getGitRepoName(
|
|
4794
|
+
name: getGitRepoName(join13(cwd, dir)) ?? dir,
|
|
4701
4795
|
path: `./${dir}`,
|
|
4702
4796
|
match: "",
|
|
4703
4797
|
base_branch: ""
|
|
@@ -4705,7 +4799,7 @@ async function detectGitRepos() {
|
|
|
4705
4799
|
}
|
|
4706
4800
|
function detectDefaultBranch(repoPath) {
|
|
4707
4801
|
try {
|
|
4708
|
-
const ref =
|
|
4802
|
+
const ref = execSync9("git symbolic-ref refs/remotes/origin/HEAD --short", {
|
|
4709
4803
|
cwd: repoPath,
|
|
4710
4804
|
encoding: "utf-8"
|
|
4711
4805
|
}).trim();
|
|
@@ -4716,7 +4810,7 @@ function detectDefaultBranch(repoPath) {
|
|
|
4716
4810
|
}
|
|
4717
4811
|
function getGitRepoName(repoPath) {
|
|
4718
4812
|
try {
|
|
4719
|
-
const url =
|
|
4813
|
+
const url = execSync9("git remote get-url origin", { cwd: repoPath, encoding: "utf-8" }).trim();
|
|
4720
4814
|
const match = url.match(/\/([^/]+?)(?:\.git)?$/) ?? url.match(/:([^/]+?)(?:\.git)?$/);
|
|
4721
4815
|
return match?.[1] ?? null;
|
|
4722
4816
|
} catch {
|