@tarcisiopgs/lisa 1.22.3 → 1.23.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.
|
@@ -675,9 +675,17 @@ function useKanbanState(bellEnabled, initialCards = []) {
|
|
|
675
675
|
const onQueued = (issue) => {
|
|
676
676
|
setCards((prev) => {
|
|
677
677
|
if (prev.some((c) => c.id === issue.id)) return prev;
|
|
678
|
+
const maxOrder = prev.reduce((max, c) => Math.max(max, c.queueOrder ?? 0), 0);
|
|
678
679
|
return [
|
|
679
680
|
...prev,
|
|
680
|
-
{
|
|
681
|
+
{
|
|
682
|
+
id: issue.id,
|
|
683
|
+
title: issue.title,
|
|
684
|
+
column: "backlog",
|
|
685
|
+
prUrls: [],
|
|
686
|
+
outputLog: "",
|
|
687
|
+
queueOrder: maxOrder + 1
|
|
688
|
+
}
|
|
681
689
|
];
|
|
682
690
|
});
|
|
683
691
|
};
|
package/dist/index.js
CHANGED
|
@@ -47,7 +47,7 @@ import {
|
|
|
47
47
|
setOutputMode,
|
|
48
48
|
updateNotice,
|
|
49
49
|
warn
|
|
50
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-W6CGBZPE.js";
|
|
51
51
|
import {
|
|
52
52
|
notify,
|
|
53
53
|
resetTitle,
|
|
@@ -659,6 +659,7 @@ var AiderProvider = class {
|
|
|
659
659
|
const errorLoopDetector = createErrorLoopDetector(proc, /^Error /);
|
|
660
660
|
const outputStall = createOutputStallDetector(proc, opts.outputStallTimeout);
|
|
661
661
|
const chunks = [];
|
|
662
|
+
const stderrChunks = [];
|
|
662
663
|
proc.stdout?.on("data", (chunk) => {
|
|
663
664
|
const raw = chunk.toString();
|
|
664
665
|
const text2 = isPty ? stripAnsi(raw) : raw;
|
|
@@ -678,6 +679,7 @@ var AiderProvider = class {
|
|
|
678
679
|
const raw = chunk.toString();
|
|
679
680
|
const text2 = isPty ? stripAnsi(raw) : raw;
|
|
680
681
|
if (getOutputMode() !== "tui") process.stderr.write(raw);
|
|
682
|
+
stderrChunks.push(text2);
|
|
681
683
|
try {
|
|
682
684
|
appendFileSync2(opts.logFile, text2);
|
|
683
685
|
} catch {
|
|
@@ -698,10 +700,15 @@ var AiderProvider = class {
|
|
|
698
700
|
} else if (overseer?.wasKilled() || errorLoopDetector.wasKilled()) {
|
|
699
701
|
chunks.push(STUCK_MESSAGE);
|
|
700
702
|
}
|
|
703
|
+
const success = exitCode === 0 && !overseer?.wasKilled() && !errorLoopDetector.wasKilled() && !outputStall.wasKilled() && !sessionTimeout.wasTimedOut();
|
|
704
|
+
if (!success && stderrChunks.length > 0) {
|
|
705
|
+
chunks.push("\n[stderr]\n", ...stderrChunks);
|
|
706
|
+
}
|
|
701
707
|
return {
|
|
702
|
-
success
|
|
708
|
+
success,
|
|
703
709
|
output: chunks.join(""),
|
|
704
|
-
duration: Date.now() - start
|
|
710
|
+
duration: Date.now() - start,
|
|
711
|
+
exitCode
|
|
705
712
|
};
|
|
706
713
|
} catch (err) {
|
|
707
714
|
return {
|
|
@@ -775,6 +782,7 @@ var ClaudeProvider = class {
|
|
|
775
782
|
const errorLoopDetector = createErrorLoopDetector(proc, /^Error /);
|
|
776
783
|
const outputStall = createOutputStallDetector(proc, opts.outputStallTimeout);
|
|
777
784
|
const chunks = [];
|
|
785
|
+
const stderrChunks = [];
|
|
778
786
|
proc.stdout?.on("data", (chunk) => {
|
|
779
787
|
const raw = chunk.toString();
|
|
780
788
|
const text2 = isPty ? stripAnsi(raw) : raw;
|
|
@@ -794,6 +802,7 @@ var ClaudeProvider = class {
|
|
|
794
802
|
const raw = chunk.toString();
|
|
795
803
|
const text2 = isPty ? stripAnsi(raw) : raw;
|
|
796
804
|
if (getOutputMode() !== "tui") process.stderr.write(raw);
|
|
805
|
+
stderrChunks.push(text2);
|
|
797
806
|
try {
|
|
798
807
|
appendFileSync3(opts.logFile, text2);
|
|
799
808
|
} catch {
|
|
@@ -814,10 +823,15 @@ var ClaudeProvider = class {
|
|
|
814
823
|
} else if (overseer?.wasKilled() || errorLoopDetector.wasKilled()) {
|
|
815
824
|
chunks.push(STUCK_MESSAGE);
|
|
816
825
|
}
|
|
826
|
+
const success = exitCode === 0 && !overseer?.wasKilled() && !errorLoopDetector.wasKilled() && !outputStall.wasKilled() && !sessionTimeout.wasTimedOut();
|
|
827
|
+
if (!success && stderrChunks.length > 0) {
|
|
828
|
+
chunks.push("\n[stderr]\n", ...stderrChunks);
|
|
829
|
+
}
|
|
817
830
|
return {
|
|
818
|
-
success
|
|
831
|
+
success,
|
|
819
832
|
output: chunks.join(""),
|
|
820
|
-
duration: Date.now() - start
|
|
833
|
+
duration: Date.now() - start,
|
|
834
|
+
exitCode
|
|
821
835
|
};
|
|
822
836
|
} catch (err) {
|
|
823
837
|
return {
|
|
@@ -878,6 +892,7 @@ var CodexProvider = class {
|
|
|
878
892
|
const errorLoopDetector = createErrorLoopDetector(proc, /^Error /);
|
|
879
893
|
const outputStall = createOutputStallDetector(proc, opts.outputStallTimeout);
|
|
880
894
|
const chunks = [];
|
|
895
|
+
const stderrChunks = [];
|
|
881
896
|
proc.stdout?.on("data", (chunk) => {
|
|
882
897
|
const raw = chunk.toString();
|
|
883
898
|
const text2 = isPty ? stripAnsi(raw) : raw;
|
|
@@ -897,6 +912,7 @@ var CodexProvider = class {
|
|
|
897
912
|
const raw = chunk.toString();
|
|
898
913
|
const text2 = isPty ? stripAnsi(raw) : raw;
|
|
899
914
|
if (getOutputMode() !== "tui") process.stderr.write(raw);
|
|
915
|
+
stderrChunks.push(text2);
|
|
900
916
|
try {
|
|
901
917
|
appendFileSync4(opts.logFile, text2);
|
|
902
918
|
} catch {
|
|
@@ -917,10 +933,15 @@ var CodexProvider = class {
|
|
|
917
933
|
} else if (overseer?.wasKilled() || errorLoopDetector.wasKilled()) {
|
|
918
934
|
chunks.push(STUCK_MESSAGE);
|
|
919
935
|
}
|
|
936
|
+
const success = exitCode === 0 && !overseer?.wasKilled() && !errorLoopDetector.wasKilled() && !outputStall.wasKilled() && !sessionTimeout.wasTimedOut();
|
|
937
|
+
if (!success && stderrChunks.length > 0) {
|
|
938
|
+
chunks.push("\n[stderr]\n", ...stderrChunks);
|
|
939
|
+
}
|
|
920
940
|
return {
|
|
921
|
-
success
|
|
941
|
+
success,
|
|
922
942
|
output: chunks.join(""),
|
|
923
|
-
duration: Date.now() - start
|
|
943
|
+
duration: Date.now() - start,
|
|
944
|
+
exitCode
|
|
924
945
|
};
|
|
925
946
|
} catch (err) {
|
|
926
947
|
return {
|
|
@@ -981,6 +1002,7 @@ var CopilotProvider = class {
|
|
|
981
1002
|
const errorLoopDetector = createErrorLoopDetector(proc, /^Error /);
|
|
982
1003
|
const outputStall = createOutputStallDetector(proc, opts.outputStallTimeout);
|
|
983
1004
|
const chunks = [];
|
|
1005
|
+
const stderrChunks = [];
|
|
984
1006
|
proc.stdout?.on("data", (chunk) => {
|
|
985
1007
|
const raw = chunk.toString();
|
|
986
1008
|
const text2 = isPty ? stripAnsi(raw) : raw;
|
|
@@ -1000,6 +1022,7 @@ var CopilotProvider = class {
|
|
|
1000
1022
|
const raw = chunk.toString();
|
|
1001
1023
|
const text2 = isPty ? stripAnsi(raw) : raw;
|
|
1002
1024
|
if (getOutputMode() !== "tui") process.stderr.write(raw);
|
|
1025
|
+
stderrChunks.push(text2);
|
|
1003
1026
|
try {
|
|
1004
1027
|
appendFileSync5(opts.logFile, text2);
|
|
1005
1028
|
} catch {
|
|
@@ -1020,10 +1043,15 @@ var CopilotProvider = class {
|
|
|
1020
1043
|
} else if (overseer?.wasKilled() || errorLoopDetector.wasKilled()) {
|
|
1021
1044
|
chunks.push(STUCK_MESSAGE);
|
|
1022
1045
|
}
|
|
1046
|
+
const success = exitCode === 0 && !overseer?.wasKilled() && !errorLoopDetector.wasKilled() && !outputStall.wasKilled() && !sessionTimeout.wasTimedOut();
|
|
1047
|
+
if (!success && stderrChunks.length > 0) {
|
|
1048
|
+
chunks.push("\n[stderr]\n", ...stderrChunks);
|
|
1049
|
+
}
|
|
1023
1050
|
return {
|
|
1024
|
-
success
|
|
1051
|
+
success,
|
|
1025
1052
|
output: chunks.join(""),
|
|
1026
|
-
duration: Date.now() - start
|
|
1053
|
+
duration: Date.now() - start,
|
|
1054
|
+
exitCode
|
|
1027
1055
|
};
|
|
1028
1056
|
} catch (err) {
|
|
1029
1057
|
return {
|
|
@@ -1102,6 +1130,7 @@ var CursorProvider = class {
|
|
|
1102
1130
|
const errorLoopDetector = createErrorLoopDetector(proc, /^Error /);
|
|
1103
1131
|
const outputStall = createOutputStallDetector(proc, opts.outputStallTimeout);
|
|
1104
1132
|
const chunks = [];
|
|
1133
|
+
const stderrChunks = [];
|
|
1105
1134
|
proc.stdout?.on("data", (chunk) => {
|
|
1106
1135
|
const raw = chunk.toString();
|
|
1107
1136
|
const text2 = isPty ? stripAnsi(raw) : raw;
|
|
@@ -1121,6 +1150,7 @@ var CursorProvider = class {
|
|
|
1121
1150
|
const raw = chunk.toString();
|
|
1122
1151
|
const text2 = isPty ? stripAnsi(raw) : raw;
|
|
1123
1152
|
if (getOutputMode() !== "tui") process.stderr.write(raw);
|
|
1153
|
+
stderrChunks.push(text2);
|
|
1124
1154
|
try {
|
|
1125
1155
|
appendFileSync6(opts.logFile, text2);
|
|
1126
1156
|
} catch {
|
|
@@ -1141,10 +1171,15 @@ var CursorProvider = class {
|
|
|
1141
1171
|
} else if (overseer?.wasKilled() || errorLoopDetector.wasKilled()) {
|
|
1142
1172
|
chunks.push(STUCK_MESSAGE);
|
|
1143
1173
|
}
|
|
1174
|
+
const success = exitCode === 0 && !overseer?.wasKilled() && !errorLoopDetector.wasKilled() && !outputStall.wasKilled() && !sessionTimeout.wasTimedOut();
|
|
1175
|
+
if (!success && stderrChunks.length > 0) {
|
|
1176
|
+
chunks.push("\n[stderr]\n", ...stderrChunks);
|
|
1177
|
+
}
|
|
1144
1178
|
return {
|
|
1145
|
-
success
|
|
1179
|
+
success,
|
|
1146
1180
|
output: chunks.join(""),
|
|
1147
|
-
duration: Date.now() - start
|
|
1181
|
+
duration: Date.now() - start,
|
|
1182
|
+
exitCode
|
|
1148
1183
|
};
|
|
1149
1184
|
} catch (err) {
|
|
1150
1185
|
return {
|
|
@@ -1204,6 +1239,7 @@ var GeminiProvider = class {
|
|
|
1204
1239
|
const errorLoopDetector = createErrorLoopDetector(proc, GEMINI_ERROR_PATTERN);
|
|
1205
1240
|
const outputStall = createOutputStallDetector(proc, opts.outputStallTimeout);
|
|
1206
1241
|
const chunks = [];
|
|
1242
|
+
const stderrChunks = [];
|
|
1207
1243
|
proc.stdout?.on("data", (chunk) => {
|
|
1208
1244
|
const raw = chunk.toString();
|
|
1209
1245
|
const text2 = isPty ? stripAnsi(raw) : raw;
|
|
@@ -1223,6 +1259,7 @@ var GeminiProvider = class {
|
|
|
1223
1259
|
const raw = chunk.toString();
|
|
1224
1260
|
const text2 = isPty ? stripAnsi(raw) : raw;
|
|
1225
1261
|
if (getOutputMode() !== "tui") process.stderr.write(raw);
|
|
1262
|
+
stderrChunks.push(text2);
|
|
1226
1263
|
try {
|
|
1227
1264
|
appendFileSync7(opts.logFile, text2);
|
|
1228
1265
|
} catch {
|
|
@@ -1243,10 +1280,15 @@ var GeminiProvider = class {
|
|
|
1243
1280
|
} else if (overseer?.wasKilled() || errorLoopDetector.wasKilled()) {
|
|
1244
1281
|
chunks.push(STUCK_MESSAGE);
|
|
1245
1282
|
}
|
|
1283
|
+
const success = exitCode === 0 && !overseer?.wasKilled() && !errorLoopDetector.wasKilled() && !outputStall.wasKilled() && !sessionTimeout.wasTimedOut();
|
|
1284
|
+
if (!success && stderrChunks.length > 0) {
|
|
1285
|
+
chunks.push("\n[stderr]\n", ...stderrChunks);
|
|
1286
|
+
}
|
|
1246
1287
|
return {
|
|
1247
|
-
success
|
|
1288
|
+
success,
|
|
1248
1289
|
output: chunks.join(""),
|
|
1249
|
-
duration: Date.now() - start
|
|
1290
|
+
duration: Date.now() - start,
|
|
1291
|
+
exitCode
|
|
1250
1292
|
};
|
|
1251
1293
|
} catch (err) {
|
|
1252
1294
|
return {
|
|
@@ -1308,6 +1350,7 @@ var GooseProvider = class {
|
|
|
1308
1350
|
const errorLoopDetector = createErrorLoopDetector(proc, /^Error /);
|
|
1309
1351
|
const outputStall = createOutputStallDetector(proc, opts.outputStallTimeout);
|
|
1310
1352
|
const chunks = [];
|
|
1353
|
+
const stderrChunks = [];
|
|
1311
1354
|
proc.stdout?.on("data", (chunk) => {
|
|
1312
1355
|
const raw = chunk.toString();
|
|
1313
1356
|
const text2 = isPty ? stripAnsi(raw) : raw;
|
|
@@ -1327,6 +1370,7 @@ var GooseProvider = class {
|
|
|
1327
1370
|
const raw = chunk.toString();
|
|
1328
1371
|
const text2 = isPty ? stripAnsi(raw) : raw;
|
|
1329
1372
|
if (getOutputMode() !== "tui") process.stderr.write(raw);
|
|
1373
|
+
stderrChunks.push(text2);
|
|
1330
1374
|
try {
|
|
1331
1375
|
appendFileSync8(opts.logFile, text2);
|
|
1332
1376
|
} catch {
|
|
@@ -1347,10 +1391,15 @@ var GooseProvider = class {
|
|
|
1347
1391
|
} else if (overseer?.wasKilled() || errorLoopDetector.wasKilled()) {
|
|
1348
1392
|
chunks.push(STUCK_MESSAGE);
|
|
1349
1393
|
}
|
|
1394
|
+
const success = exitCode === 0 && !overseer?.wasKilled() && !errorLoopDetector.wasKilled() && !outputStall.wasKilled() && !sessionTimeout.wasTimedOut();
|
|
1395
|
+
if (!success && stderrChunks.length > 0) {
|
|
1396
|
+
chunks.push("\n[stderr]\n", ...stderrChunks);
|
|
1397
|
+
}
|
|
1350
1398
|
return {
|
|
1351
|
-
success
|
|
1399
|
+
success,
|
|
1352
1400
|
output: chunks.join(""),
|
|
1353
|
-
duration: Date.now() - start
|
|
1401
|
+
duration: Date.now() - start,
|
|
1402
|
+
exitCode
|
|
1354
1403
|
};
|
|
1355
1404
|
} catch (err) {
|
|
1356
1405
|
return {
|
|
@@ -1409,6 +1458,7 @@ var OpenCodeProvider = class {
|
|
|
1409
1458
|
const errorLoopDetector = createErrorLoopDetector(proc, /^Error /);
|
|
1410
1459
|
const outputStall = createOutputStallDetector(proc, opts.outputStallTimeout);
|
|
1411
1460
|
const chunks = [];
|
|
1461
|
+
const stderrChunks = [];
|
|
1412
1462
|
proc.stdout?.on("data", (chunk) => {
|
|
1413
1463
|
const raw = chunk.toString();
|
|
1414
1464
|
const text2 = isPty ? stripAnsi(raw) : raw;
|
|
@@ -1428,6 +1478,7 @@ var OpenCodeProvider = class {
|
|
|
1428
1478
|
const raw = chunk.toString();
|
|
1429
1479
|
const text2 = isPty ? stripAnsi(raw) : raw;
|
|
1430
1480
|
if (getOutputMode() !== "tui") process.stderr.write(raw);
|
|
1481
|
+
stderrChunks.push(text2);
|
|
1431
1482
|
try {
|
|
1432
1483
|
appendFileSync9(opts.logFile, text2);
|
|
1433
1484
|
} catch {
|
|
@@ -1448,10 +1499,15 @@ var OpenCodeProvider = class {
|
|
|
1448
1499
|
} else if (overseer?.wasKilled() || errorLoopDetector.wasKilled()) {
|
|
1449
1500
|
chunks.push(STUCK_MESSAGE);
|
|
1450
1501
|
}
|
|
1502
|
+
const success = exitCode === 0 && !overseer?.wasKilled() && !errorLoopDetector.wasKilled() && !outputStall.wasKilled() && !sessionTimeout.wasTimedOut();
|
|
1503
|
+
if (!success && stderrChunks.length > 0) {
|
|
1504
|
+
chunks.push("\n[stderr]\n", ...stderrChunks);
|
|
1505
|
+
}
|
|
1451
1506
|
return {
|
|
1452
|
-
success
|
|
1507
|
+
success,
|
|
1453
1508
|
output: chunks.join(""),
|
|
1454
|
-
duration: Date.now() - start
|
|
1509
|
+
duration: Date.now() - start,
|
|
1510
|
+
exitCode
|
|
1455
1511
|
};
|
|
1456
1512
|
} catch (err) {
|
|
1457
1513
|
return {
|
|
@@ -1517,10 +1573,21 @@ var ELIGIBLE_ERROR_PATTERNS = [
|
|
|
1517
1573
|
/lisa-stall/i,
|
|
1518
1574
|
/named models unavailable/i,
|
|
1519
1575
|
/free plans can only use/i,
|
|
1520
|
-
/empty commit/i
|
|
1576
|
+
/empty commit/i,
|
|
1577
|
+
// Process crash patterns (OOM, fatal errors, signals)
|
|
1578
|
+
/heap.*out of memory/i,
|
|
1579
|
+
/out of memory/i,
|
|
1580
|
+
/FATAL ERROR/,
|
|
1581
|
+
/allocation failed/i,
|
|
1582
|
+
/segmentation fault/i,
|
|
1583
|
+
/\bSIGKILL\b/,
|
|
1584
|
+
/\bSIGABRT\b/,
|
|
1585
|
+
/\bSIGSEGV\b/
|
|
1521
1586
|
];
|
|
1522
|
-
function isEligibleForFallback(output) {
|
|
1523
|
-
|
|
1587
|
+
function isEligibleForFallback(output, exitCode) {
|
|
1588
|
+
if (ELIGIBLE_ERROR_PATTERNS.some((pattern) => pattern.test(output))) return true;
|
|
1589
|
+
if (exitCode !== void 0 && exitCode > 128) return true;
|
|
1590
|
+
return false;
|
|
1524
1591
|
}
|
|
1525
1592
|
function isCompleteProviderExhaustion(attempts) {
|
|
1526
1593
|
if (attempts.length === 0) return false;
|
|
@@ -1572,7 +1639,7 @@ async function runWithFallback(models, prompt, opts) {
|
|
|
1572
1639
|
context: extractContext(result.output)
|
|
1573
1640
|
});
|
|
1574
1641
|
}
|
|
1575
|
-
const eligible = isEligibleForFallback(result.output);
|
|
1642
|
+
const eligible = isEligibleForFallback(result.output, result.exitCode);
|
|
1576
1643
|
attempts.push({
|
|
1577
1644
|
provider: spec.provider,
|
|
1578
1645
|
model: spec.model,
|
|
@@ -7349,7 +7416,7 @@ var run = defineCommand6({
|
|
|
7349
7416
|
if (isTTY) {
|
|
7350
7417
|
const { render } = await import("ink");
|
|
7351
7418
|
const { createElement } = await import("react");
|
|
7352
|
-
const { KanbanApp } = await import("./kanban-
|
|
7419
|
+
const { KanbanApp } = await import("./kanban-QJGXJJAR.js");
|
|
7353
7420
|
const demoConfig = {
|
|
7354
7421
|
provider: "claude",
|
|
7355
7422
|
source: "linear",
|
|
@@ -7432,7 +7499,7 @@ Add them to your ${shell} and run: source ${shell}`));
|
|
|
7432
7499
|
onBeforeExit = () => persistence.stop();
|
|
7433
7500
|
const { render } = await import("ink");
|
|
7434
7501
|
const { createElement } = await import("react");
|
|
7435
|
-
const { KanbanApp } = await import("./kanban-
|
|
7502
|
+
const { KanbanApp } = await import("./kanban-QJGXJJAR.js");
|
|
7436
7503
|
render(createElement(KanbanApp, { config: merged, initialCards }), { exitOnCtrlC: false });
|
|
7437
7504
|
}
|
|
7438
7505
|
await runLoop(merged, {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
kanbanEmitter,
|
|
4
4
|
useKanbanState
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-W6CGBZPE.js";
|
|
6
6
|
import {
|
|
7
7
|
resetTitle,
|
|
8
8
|
startSpinner,
|
|
@@ -188,22 +188,14 @@ function Column({
|
|
|
188
188
|
const { columns: terminalCols, rows: terminalRows } = useTerminalSize();
|
|
189
189
|
const visibleCount = calcVisibleCount(terminalRows);
|
|
190
190
|
const cardWidth = calcCardWidth(terminalCols);
|
|
191
|
-
const sortedCards = [...cards].sort((a, b) => {
|
|
192
|
-
if (a.merged && !b.merged) return 1;
|
|
193
|
-
if (!a.merged && b.merged) return -1;
|
|
194
|
-
return 0;
|
|
195
|
-
});
|
|
196
191
|
let scrollOffset = 0;
|
|
197
192
|
if (activeCardIndex >= visibleCount) {
|
|
198
193
|
scrollOffset = activeCardIndex - visibleCount + 1;
|
|
199
194
|
}
|
|
200
|
-
scrollOffset = Math.max(
|
|
201
|
-
|
|
202
|
-
Math.min(scrollOffset, Math.max(0, sortedCards.length - visibleCount))
|
|
203
|
-
);
|
|
204
|
-
const visibleCards = sortedCards.slice(scrollOffset, scrollOffset + visibleCount);
|
|
195
|
+
scrollOffset = Math.max(0, Math.min(scrollOffset, Math.max(0, cards.length - visibleCount)));
|
|
196
|
+
const visibleCards = cards.slice(scrollOffset, scrollOffset + visibleCount);
|
|
205
197
|
const hiddenAbove = scrollOffset;
|
|
206
|
-
const hiddenBelow = Math.max(0,
|
|
198
|
+
const hiddenBelow = Math.max(0, cards.length - scrollOffset - visibleCount);
|
|
207
199
|
const borderColor = isFocused ? "yellow" : "gray";
|
|
208
200
|
const headerColor = isFocused ? "yellow" : "white";
|
|
209
201
|
const errorCount = cards.filter((c) => c.hasError).length;
|
|
@@ -732,8 +724,14 @@ function KanbanApp({ config, initialCards = [] }) {
|
|
|
732
724
|
kanbanEmitter.off("tui:exit", onExit);
|
|
733
725
|
};
|
|
734
726
|
}, [exit]);
|
|
735
|
-
const backlog = cards.filter((c) => c.column === "backlog")
|
|
736
|
-
|
|
727
|
+
const backlog = [...cards.filter((c) => c.column === "backlog")].sort((a, b) => {
|
|
728
|
+
if (a.hasError && !b.hasError) return 1;
|
|
729
|
+
if (!a.hasError && b.hasError) return -1;
|
|
730
|
+
return (a.queueOrder ?? 0) - (b.queueOrder ?? 0);
|
|
731
|
+
});
|
|
732
|
+
const inProgress = [...cards.filter((c) => c.column === "in_progress")].sort(
|
|
733
|
+
(a, b) => (a.startedAt ?? 0) - (b.startedAt ?? 0)
|
|
734
|
+
);
|
|
737
735
|
const hasInProgress = inProgress.length > 0;
|
|
738
736
|
useEffect4(() => {
|
|
739
737
|
if (workComplete) {
|
|
@@ -746,7 +744,11 @@ function KanbanApp({ config, initialCards = [] }) {
|
|
|
746
744
|
}
|
|
747
745
|
return () => resetTitle();
|
|
748
746
|
}, [inProgress, workComplete]);
|
|
749
|
-
const done = cards.filter((c) => c.column === "done")
|
|
747
|
+
const done = [...cards.filter((c) => c.column === "done")].sort((a, b) => {
|
|
748
|
+
if (a.merged && !b.merged) return 1;
|
|
749
|
+
if (!a.merged && b.merged) return -1;
|
|
750
|
+
return (b.finishedAt ?? 0) - (a.finishedAt ?? 0);
|
|
751
|
+
});
|
|
750
752
|
const columnCards = [backlog, inProgress, done];
|
|
751
753
|
useEffect4(() => {
|
|
752
754
|
if (!selectedCardId || activeView !== "detail") return;
|