@tarcisiopgs/lisa 1.14.2 → 1.15.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.
|
@@ -640,6 +640,7 @@ function useKanbanState(bellEnabled) {
|
|
|
640
640
|
const [cards, setCards] = useState([]);
|
|
641
641
|
const [isEmpty, setIsEmpty] = useState(false);
|
|
642
642
|
const [isWatching, setIsWatching] = useState(false);
|
|
643
|
+
const [isWatchPrompt, setIsWatchPrompt] = useState(false);
|
|
643
644
|
const [workComplete, setWorkComplete] = useState(
|
|
644
645
|
null
|
|
645
646
|
);
|
|
@@ -763,10 +764,17 @@ function useKanbanState(bellEnabled) {
|
|
|
763
764
|
const onComplete = (data) => setWorkComplete(data);
|
|
764
765
|
const onWatching = () => setIsWatching(true);
|
|
765
766
|
const onWatchResume = () => setIsWatching(false);
|
|
767
|
+
const onWatchPrompt = () => {
|
|
768
|
+
setIsWatchPrompt(true);
|
|
769
|
+
setIsWatching(false);
|
|
770
|
+
};
|
|
771
|
+
const onWatchPromptResolved = () => setIsWatchPrompt(false);
|
|
766
772
|
kanbanEmitter.on("work:empty", onEmpty);
|
|
767
773
|
kanbanEmitter.on("work:complete", onComplete);
|
|
768
774
|
kanbanEmitter.on("work:watching", onWatching);
|
|
769
775
|
kanbanEmitter.on("work:watch-resume", onWatchResume);
|
|
776
|
+
kanbanEmitter.on("work:watch-prompt", onWatchPrompt);
|
|
777
|
+
kanbanEmitter.on("work:watch-prompt-resolved", onWatchPromptResolved);
|
|
770
778
|
const cleanupBell = registerBellListeners(bellEnabled);
|
|
771
779
|
return () => {
|
|
772
780
|
kanbanEmitter.off("issue:queued", onQueued);
|
|
@@ -784,13 +792,15 @@ function useKanbanState(bellEnabled) {
|
|
|
784
792
|
kanbanEmitter.off("work:complete", onComplete);
|
|
785
793
|
kanbanEmitter.off("work:watching", onWatching);
|
|
786
794
|
kanbanEmitter.off("work:watch-resume", onWatchResume);
|
|
795
|
+
kanbanEmitter.off("work:watch-prompt", onWatchPrompt);
|
|
796
|
+
kanbanEmitter.off("work:watch-prompt-resolved", onWatchPromptResolved);
|
|
787
797
|
cleanupBell();
|
|
788
798
|
for (const issueId of activePolls.keys()) {
|
|
789
799
|
stopMergePolling(issueId);
|
|
790
800
|
}
|
|
791
801
|
};
|
|
792
802
|
}, [bellEnabled]);
|
|
793
|
-
return { cards, isEmpty, isWatching, workComplete, modelInUse };
|
|
803
|
+
return { cards, isEmpty, isWatching, isWatchPrompt, workComplete, modelInUse };
|
|
794
804
|
}
|
|
795
805
|
|
|
796
806
|
export {
|
package/dist/index.js
CHANGED
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
ok,
|
|
33
33
|
setOutputMode,
|
|
34
34
|
warn
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-WZIPTRJL.js";
|
|
36
36
|
import {
|
|
37
37
|
notify,
|
|
38
38
|
resetTitle,
|
|
@@ -363,6 +363,18 @@ function determineRepoPath(repos, issue2, workspace) {
|
|
|
363
363
|
const first = repos[0];
|
|
364
364
|
return first ? join(workspace, first.path) : void 0;
|
|
365
365
|
}
|
|
366
|
+
async function hasCodeChanges(repoPath, baseBranch) {
|
|
367
|
+
try {
|
|
368
|
+
const { stdout } = await execa("git", ["diff", "--stat", `${baseBranch}..HEAD`], {
|
|
369
|
+
cwd: repoPath,
|
|
370
|
+
reject: false
|
|
371
|
+
});
|
|
372
|
+
const trimmed = stdout.trim();
|
|
373
|
+
return trimmed.length > 0;
|
|
374
|
+
} catch {
|
|
375
|
+
return false;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
366
378
|
|
|
367
379
|
// src/providers/aider.ts
|
|
368
380
|
import { execSync } from "child_process";
|
|
@@ -1263,7 +1275,8 @@ var ELIGIBLE_ERROR_PATTERNS = [
|
|
|
1263
1275
|
/command not found/i,
|
|
1264
1276
|
/lisa-overseer/i,
|
|
1265
1277
|
/named models unavailable/i,
|
|
1266
|
-
/free plans can only use/i
|
|
1278
|
+
/free plans can only use/i,
|
|
1279
|
+
/empty commit/i
|
|
1267
1280
|
];
|
|
1268
1281
|
function isEligibleForFallback(output) {
|
|
1269
1282
|
return ELIGIBLE_ERROR_PATTERNS.some((pattern) => pattern.test(output));
|
|
@@ -3686,6 +3699,7 @@ var userKilledSet = /* @__PURE__ */ new Set();
|
|
|
3686
3699
|
var userSkippedSet = /* @__PURE__ */ new Set();
|
|
3687
3700
|
var _shuttingDown = false;
|
|
3688
3701
|
var _loopPaused = false;
|
|
3702
|
+
var _userQuitFromWatchPrompt = false;
|
|
3689
3703
|
function isShuttingDown() {
|
|
3690
3704
|
return _shuttingDown;
|
|
3691
3705
|
}
|
|
@@ -3695,6 +3709,9 @@ function setShuttingDown(value) {
|
|
|
3695
3709
|
function isLoopPaused() {
|
|
3696
3710
|
return _loopPaused;
|
|
3697
3711
|
}
|
|
3712
|
+
function hasUserQuitFromWatchPrompt() {
|
|
3713
|
+
return _userQuitFromWatchPrompt;
|
|
3714
|
+
}
|
|
3698
3715
|
function killProviderForIssue(issueId) {
|
|
3699
3716
|
const pid = activeProviderPids.get(issueId);
|
|
3700
3717
|
if (!pid) return;
|
|
@@ -3792,6 +3809,10 @@ function setupEventListeners() {
|
|
|
3792
3809
|
}
|
|
3793
3810
|
}
|
|
3794
3811
|
});
|
|
3812
|
+
kanbanEmitter.on("loop:quit", () => {
|
|
3813
|
+
_userQuitFromWatchPrompt = true;
|
|
3814
|
+
setShuttingDown(true);
|
|
3815
|
+
});
|
|
3795
3816
|
}
|
|
3796
3817
|
|
|
3797
3818
|
// src/loop/helpers.ts
|
|
@@ -6003,6 +6024,34 @@ ${result.output}
|
|
|
6003
6024
|
cleanupManifest(workspace, issue2.id);
|
|
6004
6025
|
return { success: false, providerUsed: result.providerUsed, prUrls: [], fallback: result };
|
|
6005
6026
|
}
|
|
6027
|
+
const hasChanges = await hasCodeChanges(repoPath, _defaultBranch);
|
|
6028
|
+
if (!hasChanges) {
|
|
6029
|
+
error(
|
|
6030
|
+
`Provider reported success but no code changes detected. Treating as failure for ${issue2.id}.`
|
|
6031
|
+
);
|
|
6032
|
+
cleanupManifest(workspace, issue2.id);
|
|
6033
|
+
const emptyCommitResult = {
|
|
6034
|
+
success: false,
|
|
6035
|
+
output: "Provider reported success but no code changes detected",
|
|
6036
|
+
duration: result.duration,
|
|
6037
|
+
providerUsed: result.providerUsed,
|
|
6038
|
+
attempts: [
|
|
6039
|
+
{
|
|
6040
|
+
provider: result.providerUsed,
|
|
6041
|
+
model: "",
|
|
6042
|
+
success: false,
|
|
6043
|
+
error: "Eligible error (empty commit)",
|
|
6044
|
+
duration: result.duration
|
|
6045
|
+
}
|
|
6046
|
+
]
|
|
6047
|
+
};
|
|
6048
|
+
return {
|
|
6049
|
+
success: false,
|
|
6050
|
+
providerUsed: result.providerUsed,
|
|
6051
|
+
prUrls: [],
|
|
6052
|
+
fallback: emptyCommitResult
|
|
6053
|
+
};
|
|
6054
|
+
}
|
|
6006
6055
|
const manifest = readLisaManifest(workspace, issue2.id);
|
|
6007
6056
|
cleanupManifest(workspace, issue2.id);
|
|
6008
6057
|
let prUrl = manifest?.prUrl;
|
|
@@ -6131,6 +6180,34 @@ ${result.output}
|
|
|
6131
6180
|
await cleanupWorktree(repoPath, worktreePath);
|
|
6132
6181
|
return { success: false, providerUsed: result.providerUsed, prUrls: [], fallback: result };
|
|
6133
6182
|
}
|
|
6183
|
+
const hasChanges = await hasCodeChanges(worktreePath, baseBranch);
|
|
6184
|
+
if (!hasChanges) {
|
|
6185
|
+
error(
|
|
6186
|
+
`Provider reported success but no code changes detected. Treating as failure for ${issue2.id}.`
|
|
6187
|
+
);
|
|
6188
|
+
await cleanupWorktree(repoPath, worktreePath);
|
|
6189
|
+
const emptyCommitResult = {
|
|
6190
|
+
success: false,
|
|
6191
|
+
output: "Provider reported success but no code changes detected",
|
|
6192
|
+
duration: result.duration,
|
|
6193
|
+
providerUsed: result.providerUsed,
|
|
6194
|
+
attempts: [
|
|
6195
|
+
{
|
|
6196
|
+
provider: result.providerUsed,
|
|
6197
|
+
model: "",
|
|
6198
|
+
success: false,
|
|
6199
|
+
error: "Eligible error (empty commit)",
|
|
6200
|
+
duration: result.duration
|
|
6201
|
+
}
|
|
6202
|
+
]
|
|
6203
|
+
};
|
|
6204
|
+
return {
|
|
6205
|
+
success: false,
|
|
6206
|
+
providerUsed: result.providerUsed,
|
|
6207
|
+
prUrls: [],
|
|
6208
|
+
fallback: emptyCommitResult
|
|
6209
|
+
};
|
|
6210
|
+
}
|
|
6134
6211
|
const manifest = readManifestFile(manifestPath);
|
|
6135
6212
|
let prUrl = manifest?.prUrl;
|
|
6136
6213
|
if (!prUrl) {
|
|
@@ -6269,6 +6346,18 @@ async function runConcurrentLoop(config2, source, models, workspace, opts) {
|
|
|
6269
6346
|
if (!issue2) {
|
|
6270
6347
|
if (opts.watch) {
|
|
6271
6348
|
if (activeWorkers.size === 0) {
|
|
6349
|
+
if (completedCount > 0) {
|
|
6350
|
+
ok(`All issues resolved. Prompting user to continue watching...`);
|
|
6351
|
+
kanbanEmitter.emit("work:watch-prompt");
|
|
6352
|
+
setTitle("Lisa \u2014 all resolved");
|
|
6353
|
+
await waitIfPaused();
|
|
6354
|
+
if (hasUserQuitFromWatchPrompt() || isShuttingDown()) {
|
|
6355
|
+
noMoreIssues = true;
|
|
6356
|
+
break;
|
|
6357
|
+
}
|
|
6358
|
+
kanbanEmitter.emit("work:watch-prompt-resumed");
|
|
6359
|
+
ok(`Resuming watch mode (polling every ${WATCH_POLL_INTERVAL_MS / 1e3}s)...`);
|
|
6360
|
+
}
|
|
6272
6361
|
ok(
|
|
6273
6362
|
`No issues ready. Watching for new issues (polling every ${WATCH_POLL_INTERVAL_MS / 1e3}s)...`
|
|
6274
6363
|
);
|
|
@@ -6461,6 +6550,33 @@ ${result.output}
|
|
|
6461
6550
|
error(`Session ${session} failed for ${issue2.id}. Check ${logFile}`);
|
|
6462
6551
|
return { success: false, providerUsed: result.providerUsed, prUrls: [], fallback: result };
|
|
6463
6552
|
}
|
|
6553
|
+
const hasChanges = await hasCodeChanges(workspace, config2.base_branch);
|
|
6554
|
+
if (!hasChanges) {
|
|
6555
|
+
error(
|
|
6556
|
+
`Provider reported success but no code changes detected. Treating as failure for ${issue2.id}.`
|
|
6557
|
+
);
|
|
6558
|
+
const emptyCommitResult = {
|
|
6559
|
+
success: false,
|
|
6560
|
+
output: "Provider reported success but no code changes detected",
|
|
6561
|
+
duration: result.duration,
|
|
6562
|
+
providerUsed: result.providerUsed,
|
|
6563
|
+
attempts: [
|
|
6564
|
+
{
|
|
6565
|
+
provider: result.providerUsed,
|
|
6566
|
+
model: "",
|
|
6567
|
+
success: false,
|
|
6568
|
+
error: "Eligible error (empty commit)",
|
|
6569
|
+
duration: result.duration
|
|
6570
|
+
}
|
|
6571
|
+
]
|
|
6572
|
+
};
|
|
6573
|
+
return {
|
|
6574
|
+
success: false,
|
|
6575
|
+
providerUsed: result.providerUsed,
|
|
6576
|
+
prUrls: [],
|
|
6577
|
+
fallback: emptyCommitResult
|
|
6578
|
+
};
|
|
6579
|
+
}
|
|
6464
6580
|
const manifest = readManifestFile(manifestPath);
|
|
6465
6581
|
try {
|
|
6466
6582
|
unlinkSync11(manifestPath);
|
|
@@ -6556,6 +6672,23 @@ async function runSequentialLoop(config2, source, models, workspace, opts) {
|
|
|
6556
6672
|
break;
|
|
6557
6673
|
}
|
|
6558
6674
|
if (opts.watch) {
|
|
6675
|
+
if (completedCount > 0) {
|
|
6676
|
+
ok(`All issues resolved. Prompting user to continue watching...`);
|
|
6677
|
+
kanbanEmitter.emit("work:watch-prompt");
|
|
6678
|
+
setTitle("Lisa \u2014 all resolved");
|
|
6679
|
+
await waitIfPaused();
|
|
6680
|
+
if (hasUserQuitFromWatchPrompt() || isShuttingDown()) {
|
|
6681
|
+
break;
|
|
6682
|
+
}
|
|
6683
|
+
kanbanEmitter.emit("work:watch-prompt-resumed");
|
|
6684
|
+
ok(`Resuming watch mode (polling every ${WATCH_POLL_INTERVAL_MS / 1e3}s)...`);
|
|
6685
|
+
kanbanEmitter.emit("work:watching");
|
|
6686
|
+
setTitle("Lisa \u2014 watching...");
|
|
6687
|
+
await sleep2(WATCH_POLL_INTERVAL_MS);
|
|
6688
|
+
kanbanEmitter.emit("work:watch-resume");
|
|
6689
|
+
session--;
|
|
6690
|
+
continue;
|
|
6691
|
+
}
|
|
6559
6692
|
ok(
|
|
6560
6693
|
`No issues ready. Watching for new issues (polling every ${WATCH_POLL_INTERVAL_MS / 1e3}s)...`
|
|
6561
6694
|
);
|
|
@@ -6903,7 +7036,7 @@ var run = defineCommand5({
|
|
|
6903
7036
|
if (isTTY) {
|
|
6904
7037
|
const { render } = await import("ink");
|
|
6905
7038
|
const { createElement } = await import("react");
|
|
6906
|
-
const { KanbanApp } = await import("./kanban-
|
|
7039
|
+
const { KanbanApp } = await import("./kanban-ECJSRP4C.js");
|
|
6907
7040
|
const demoConfig = {
|
|
6908
7041
|
provider: "claude",
|
|
6909
7042
|
source: "linear",
|
|
@@ -6972,7 +7105,7 @@ Add them to your ${shell} and run: source ${shell}`));
|
|
|
6972
7105
|
if (isTTY) {
|
|
6973
7106
|
const { render } = await import("ink");
|
|
6974
7107
|
const { createElement } = await import("react");
|
|
6975
|
-
const { KanbanApp } = await import("./kanban-
|
|
7108
|
+
const { KanbanApp } = await import("./kanban-ECJSRP4C.js");
|
|
6976
7109
|
render(createElement(KanbanApp, { config: merged }), { exitOnCtrlC: false });
|
|
6977
7110
|
}
|
|
6978
7111
|
await runLoop(merged, {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
kanbanEmitter,
|
|
4
4
|
useKanbanState
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-WZIPTRJL.js";
|
|
6
6
|
import {
|
|
7
7
|
resetTitle,
|
|
8
8
|
startSpinner,
|
|
@@ -56,21 +56,6 @@ function wrapTitle(title, maxWidth) {
|
|
|
56
56
|
const line2 = remaining.length > maxWidth ? `${remaining.slice(0, maxWidth - 1)}\u2026` : remaining;
|
|
57
57
|
return [line1, line2];
|
|
58
58
|
}
|
|
59
|
-
function getLastOutputLine(outputLog, maxWidth) {
|
|
60
|
-
if (!outputLog) return "";
|
|
61
|
-
const ansiPattern = /\x1B(?:\[[0-?]*[ -/]*[@-~]|\].*?(?:\x07|\x1B\\))/g;
|
|
62
|
-
const stripped = outputLog.replace(ansiPattern, "");
|
|
63
|
-
const lines = stripped.split(/\r?\n/).map((line) => {
|
|
64
|
-
const parts = line.split("\r");
|
|
65
|
-
return (parts[parts.length - 1] ?? "").trim();
|
|
66
|
-
}).filter((line) => line.length > 0);
|
|
67
|
-
if (lines.length === 0) return "";
|
|
68
|
-
const lastLine = lines[lines.length - 1] ?? "";
|
|
69
|
-
if (lastLine.length > maxWidth) {
|
|
70
|
-
return `${lastLine.slice(0, maxWidth - 1)}\u2026`;
|
|
71
|
-
}
|
|
72
|
-
return lastLine;
|
|
73
|
-
}
|
|
74
59
|
function Card({
|
|
75
60
|
card,
|
|
76
61
|
isSelected = false,
|
|
@@ -134,9 +119,7 @@ function Card({
|
|
|
134
119
|
] }),
|
|
135
120
|
/* @__PURE__ */ jsx(Text, { bold: isSelected, dimColor: !isSelected, children: stripDoubleWidth(titleLine1).padEnd(cardWidth) }),
|
|
136
121
|
/* @__PURE__ */ jsx(Text, { bold: isSelected, dimColor: !isSelected, children: stripDoubleWidth(titleLine2).padEnd(cardWidth) }),
|
|
137
|
-
/* @__PURE__ */ jsx(Text, {
|
|
138
|
-
card.column === "in_progress" ? getLastOutputLine(card.outputLog, cardWidth) : ""
|
|
139
|
-
).padEnd(cardWidth) }),
|
|
122
|
+
/* @__PURE__ */ jsx(Text, { children: " ".repeat(cardWidth) }),
|
|
140
123
|
card.column === "in_progress" ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", marginTop: 0, children: [
|
|
141
124
|
isPausedInProgress ? /* @__PURE__ */ jsx(Text, { color: "gray", children: "\u23F8" }) : /* @__PURE__ */ jsx(Text, { color: "yellow", children: /* @__PURE__ */ jsx(Spinner, { type: "dots" }) }),
|
|
142
125
|
/* @__PURE__ */ jsx(Text, { color: isPausedInProgress ? "gray" : "yellow", dimColor: isPausedInProgress, children: elapsedMs !== null ? ` ${formatElapsed(elapsedMs)}` : "" })
|
|
@@ -220,7 +203,6 @@ function Column({
|
|
|
220
203
|
const hiddenBelow = Math.max(0, sortedCards.length - scrollOffset - visibleCount);
|
|
221
204
|
const borderColor = isFocused ? "yellow" : "gray";
|
|
222
205
|
const headerColor = isFocused ? "yellow" : "white";
|
|
223
|
-
const runningCount = cards.filter((c) => c.column === "in_progress").length;
|
|
224
206
|
const errorCount = cards.filter((c) => c.hasError).length;
|
|
225
207
|
return /* @__PURE__ */ jsxs2(
|
|
226
208
|
Box2,
|
|
@@ -241,7 +223,6 @@ function Column({
|
|
|
241
223
|
] }),
|
|
242
224
|
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "row", children: [
|
|
243
225
|
errorCount > 0 && /* @__PURE__ */ jsx2(Text2, { color: "red", bold: true, children: `\u2716${errorCount} ` }),
|
|
244
|
-
runningCount > 0 && /* @__PURE__ */ jsx2(Text2, { color: "yellow", children: `\u25CF${runningCount} ` }),
|
|
245
226
|
/* @__PURE__ */ jsx2(Text2, { color: headerColor, children: `[${cards.length}]` })
|
|
246
227
|
] })
|
|
247
228
|
] }),
|
|
@@ -268,7 +249,7 @@ function Column({
|
|
|
268
249
|
}
|
|
269
250
|
|
|
270
251
|
// src/ui/board.tsx
|
|
271
|
-
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
252
|
+
import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
272
253
|
function formatDuration(ms) {
|
|
273
254
|
const totalSeconds = Math.floor(ms / 1e3);
|
|
274
255
|
const minutes = Math.floor(totalSeconds / 60);
|
|
@@ -281,6 +262,7 @@ function Board({
|
|
|
281
262
|
labels,
|
|
282
263
|
isEmpty,
|
|
283
264
|
isWatching = false,
|
|
265
|
+
isWatchPrompt = false,
|
|
284
266
|
workComplete,
|
|
285
267
|
activeColIndex = 0,
|
|
286
268
|
activeCardIndex = 0,
|
|
@@ -303,7 +285,36 @@ function Board({
|
|
|
303
285
|
/* @__PURE__ */ jsx3(Box3, { height: 1 }),
|
|
304
286
|
/* @__PURE__ */ jsx3(Text3, { color: "white", dimColor: true, children: "Polling every 60s for new issues with the ready label." }),
|
|
305
287
|
/* @__PURE__ */ jsx3(Box3, { height: 1 }),
|
|
306
|
-
/* @__PURE__ */ jsx3(Text3, { color: "gray", dimColor: true, children: "Press
|
|
288
|
+
/* @__PURE__ */ jsx3(Text3, { color: "gray", dimColor: true, children: "Press [q] to quit" })
|
|
289
|
+
]
|
|
290
|
+
}
|
|
291
|
+
) });
|
|
292
|
+
}
|
|
293
|
+
if (isWatchPrompt) {
|
|
294
|
+
return /* @__PURE__ */ jsx3(Box3, { flexGrow: 1, alignItems: "center", justifyContent: "center", children: /* @__PURE__ */ jsxs3(
|
|
295
|
+
Box3,
|
|
296
|
+
{
|
|
297
|
+
flexDirection: "column",
|
|
298
|
+
borderStyle: "single",
|
|
299
|
+
borderColor: "green",
|
|
300
|
+
paddingX: 3,
|
|
301
|
+
paddingY: 1,
|
|
302
|
+
children: [
|
|
303
|
+
workComplete && /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
304
|
+
/* @__PURE__ */ jsx3(Text3, { color: "green", bold: true, children: `\u25C8 ${workComplete.total} issue${workComplete.total !== 1 ? "s" : ""} resolved` }),
|
|
305
|
+
/* @__PURE__ */ jsx3(Box3, { height: 1 })
|
|
306
|
+
] }),
|
|
307
|
+
/* @__PURE__ */ jsx3(Text3, { color: "cyan", bold: true, children: "\u25CE CONTINUE WATCHING?" }),
|
|
308
|
+
/* @__PURE__ */ jsx3(Box3, { height: 1 }),
|
|
309
|
+
/* @__PURE__ */ jsx3(Text3, { color: "white", dimColor: true, children: "All issues have been processed." }),
|
|
310
|
+
/* @__PURE__ */ jsx3(Box3, { height: 1 }),
|
|
311
|
+
/* @__PURE__ */ jsxs3(Text3, { color: "gray", dimColor: true, children: [
|
|
312
|
+
"[",
|
|
313
|
+
/* @__PURE__ */ jsx3(Text3, { color: "cyan", bold: true, children: "w" }),
|
|
314
|
+
"] Watch / [",
|
|
315
|
+
/* @__PURE__ */ jsx3(Text3, { color: "cyan", bold: true, children: "q" }),
|
|
316
|
+
"] Quit"
|
|
317
|
+
] })
|
|
307
318
|
]
|
|
308
319
|
}
|
|
309
320
|
) });
|
|
@@ -655,7 +666,7 @@ function Sidebar({
|
|
|
655
666
|
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
656
667
|
function KanbanApp({ config }) {
|
|
657
668
|
const { exit } = useApp();
|
|
658
|
-
const { cards, isEmpty, isWatching, workComplete, modelInUse } = useKanbanState(
|
|
669
|
+
const { cards, isEmpty, isWatching, isWatchPrompt, workComplete, modelInUse } = useKanbanState(
|
|
659
670
|
config.bell ?? true
|
|
660
671
|
);
|
|
661
672
|
const { rows } = useTerminalSize();
|
|
@@ -712,6 +723,18 @@ function KanbanApp({ config }) {
|
|
|
712
723
|
setActiveCardIndex(newCardIndex);
|
|
713
724
|
}, [cards, selectedCardId, activeView]);
|
|
714
725
|
useInput2((input, key) => {
|
|
726
|
+
if (isWatchPrompt) {
|
|
727
|
+
if (input === "w") {
|
|
728
|
+
kanbanEmitter.emit("work:watch-prompt-resolved");
|
|
729
|
+
kanbanEmitter.emit("loop:resume");
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
if (input === "q") {
|
|
733
|
+
kanbanEmitter.emit("loop:quit");
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
return;
|
|
737
|
+
}
|
|
715
738
|
if (input === "q") {
|
|
716
739
|
process.emit("SIGINT");
|
|
717
740
|
return;
|
|
@@ -810,6 +833,7 @@ function KanbanApp({ config }) {
|
|
|
810
833
|
labels,
|
|
811
834
|
isEmpty,
|
|
812
835
|
isWatching,
|
|
836
|
+
isWatchPrompt,
|
|
813
837
|
workComplete,
|
|
814
838
|
activeColIndex,
|
|
815
839
|
activeCardIndex,
|