@ondrej-svec/hog 1.21.1 → 1.22.1
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/dist/cli.js +499 -162
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2896,7 +2896,8 @@ function useKeyboard({
|
|
|
2896
2896
|
onRepoEnter,
|
|
2897
2897
|
onStatusEnter,
|
|
2898
2898
|
onActivityEnter,
|
|
2899
|
-
showDetailPanel
|
|
2899
|
+
showDetailPanel,
|
|
2900
|
+
leftPanelHidden
|
|
2900
2901
|
}) {
|
|
2901
2902
|
const {
|
|
2902
2903
|
exit,
|
|
@@ -2918,7 +2919,9 @@ function useKeyboard({
|
|
|
2918
2919
|
handleToggleLog,
|
|
2919
2920
|
handleLaunchClaude,
|
|
2920
2921
|
handleEnterWorkflow,
|
|
2921
|
-
handleEnterTriage
|
|
2922
|
+
handleEnterTriage,
|
|
2923
|
+
handleToggleLeftPanel,
|
|
2924
|
+
handleToggleZen
|
|
2922
2925
|
} = actions;
|
|
2923
2926
|
const handleInput = useCallback6(
|
|
2924
2927
|
(input2, key) => {
|
|
@@ -2926,6 +2929,29 @@ function useKeyboard({
|
|
|
2926
2929
|
ui.toggleHelp();
|
|
2927
2930
|
return;
|
|
2928
2931
|
}
|
|
2932
|
+
if (ui.state.mode === "zen") {
|
|
2933
|
+
if (input2 === "Z" || key.escape) {
|
|
2934
|
+
handleToggleZen();
|
|
2935
|
+
return;
|
|
2936
|
+
}
|
|
2937
|
+
if (input2 === "j" || key.downArrow) {
|
|
2938
|
+
nav.moveDown();
|
|
2939
|
+
return;
|
|
2940
|
+
}
|
|
2941
|
+
if (input2 === "k" || key.upArrow) {
|
|
2942
|
+
nav.moveUp();
|
|
2943
|
+
return;
|
|
2944
|
+
}
|
|
2945
|
+
if (input2 === "C") {
|
|
2946
|
+
handleLaunchClaude();
|
|
2947
|
+
return;
|
|
2948
|
+
}
|
|
2949
|
+
if (input2 === "q") {
|
|
2950
|
+
exit();
|
|
2951
|
+
return;
|
|
2952
|
+
}
|
|
2953
|
+
return;
|
|
2954
|
+
}
|
|
2929
2955
|
if (key.escape && ui.state.mode !== "focus") {
|
|
2930
2956
|
if (ui.state.mode === "multiSelect") {
|
|
2931
2957
|
multiSelect.clear();
|
|
@@ -3039,6 +3065,9 @@ function useKeyboard({
|
|
|
3039
3065
|
if (ui.canAct) {
|
|
3040
3066
|
const digit = parseInt(input2, 10);
|
|
3041
3067
|
if (!Number.isNaN(digit) && digit >= 0 && digit <= 4) {
|
|
3068
|
+
if (leftPanelHidden && (digit === 1 || digit === 2)) {
|
|
3069
|
+
return;
|
|
3070
|
+
}
|
|
3042
3071
|
if (digit === 0 && !showDetailPanel) {
|
|
3043
3072
|
ui.enterDetail();
|
|
3044
3073
|
} else {
|
|
@@ -3113,6 +3142,14 @@ function useKeyboard({
|
|
|
3113
3142
|
handleEnterFuzzyPicker();
|
|
3114
3143
|
return;
|
|
3115
3144
|
}
|
|
3145
|
+
if (input2 === "H") {
|
|
3146
|
+
handleToggleLeftPanel();
|
|
3147
|
+
return;
|
|
3148
|
+
}
|
|
3149
|
+
if (input2 === "Z") {
|
|
3150
|
+
handleToggleZen();
|
|
3151
|
+
return;
|
|
3152
|
+
}
|
|
3116
3153
|
if (input2 === " ") {
|
|
3117
3154
|
const id = nav.selectedId;
|
|
3118
3155
|
if (id) {
|
|
@@ -3180,10 +3217,13 @@ function useKeyboard({
|
|
|
3180
3217
|
handleLaunchClaude,
|
|
3181
3218
|
handleEnterWorkflow,
|
|
3182
3219
|
handleEnterTriage,
|
|
3183
|
-
|
|
3220
|
+
handleToggleLeftPanel,
|
|
3221
|
+
handleToggleZen,
|
|
3222
|
+
showDetailPanel,
|
|
3223
|
+
leftPanelHidden
|
|
3184
3224
|
]
|
|
3185
3225
|
);
|
|
3186
|
-
const inputActive = ui.state.mode === "normal" || ui.state.mode === "multiSelect" || ui.state.mode === "focus" || ui.state.mode === "overlay:detail";
|
|
3226
|
+
const inputActive = ui.state.mode === "normal" || ui.state.mode === "multiSelect" || ui.state.mode === "focus" || ui.state.mode === "overlay:detail" || ui.state.mode === "zen";
|
|
3187
3227
|
useInput(handleInput, { isActive: inputActive });
|
|
3188
3228
|
const handleSearchEscape = useCallback6(
|
|
3189
3229
|
(_input, key) => {
|
|
@@ -3815,6 +3855,12 @@ function uiReducer(state, action) {
|
|
|
3815
3855
|
case "ENTER_TRIAGE":
|
|
3816
3856
|
if (state.mode !== "normal") return state;
|
|
3817
3857
|
return { ...state, mode: "overlay:triage", previousMode: "normal" };
|
|
3858
|
+
case "ENTER_ZEN":
|
|
3859
|
+
if (state.mode !== "normal") return state;
|
|
3860
|
+
return { ...state, mode: "zen", previousMode: "normal" };
|
|
3861
|
+
case "EXIT_ZEN":
|
|
3862
|
+
if (state.mode !== "zen") return state;
|
|
3863
|
+
return { ...state, mode: "normal", previousMode: "normal" };
|
|
3818
3864
|
case "TOGGLE_HELP":
|
|
3819
3865
|
return { ...state, helpVisible: !state.helpVisible };
|
|
3820
3866
|
case "EXIT_OVERLAY":
|
|
@@ -3835,7 +3881,7 @@ function uiReducer(state, action) {
|
|
|
3835
3881
|
}
|
|
3836
3882
|
function canNavigate(state) {
|
|
3837
3883
|
const { mode } = state;
|
|
3838
|
-
return mode === "normal" || mode === "multiSelect" || mode === "focus";
|
|
3884
|
+
return mode === "normal" || mode === "multiSelect" || mode === "focus" || mode === "zen";
|
|
3839
3885
|
}
|
|
3840
3886
|
function canAct(state) {
|
|
3841
3887
|
return state.mode === "normal";
|
|
@@ -3863,6 +3909,8 @@ function useUIState() {
|
|
|
3863
3909
|
enterWorkflow: useCallback11(() => dispatch({ type: "ENTER_WORKFLOW" }), []),
|
|
3864
3910
|
enterNudge: useCallback11(() => dispatch({ type: "ENTER_NUDGE" }), []),
|
|
3865
3911
|
enterTriage: useCallback11(() => dispatch({ type: "ENTER_TRIAGE" }), []),
|
|
3912
|
+
enterZen: useCallback11(() => dispatch({ type: "ENTER_ZEN" }), []),
|
|
3913
|
+
exitZen: useCallback11(() => dispatch({ type: "EXIT_ZEN" }), []),
|
|
3866
3914
|
toggleHelp: useCallback11(() => dispatch({ type: "TOGGLE_HELP" }), []),
|
|
3867
3915
|
exitOverlay: useCallback11(() => dispatch({ type: "EXIT_OVERLAY" }), []),
|
|
3868
3916
|
exitToNormal: useCallback11(() => dispatch({ type: "EXIT_TO_NORMAL" }), []),
|
|
@@ -3971,9 +4019,257 @@ var init_use_workflow_state = __esm({
|
|
|
3971
4019
|
}
|
|
3972
4020
|
});
|
|
3973
4021
|
|
|
4022
|
+
// src/board/tmux-pane.ts
|
|
4023
|
+
import { execFileSync as execFileSync3 } from "child_process";
|
|
4024
|
+
function agentWindowName(issueNumber) {
|
|
4025
|
+
return `claude-${issueNumber}`;
|
|
4026
|
+
}
|
|
4027
|
+
function windowExists(windowName) {
|
|
4028
|
+
try {
|
|
4029
|
+
const output = execFileSync3("tmux", ["list-windows", "-F", "#{window_name}"], {
|
|
4030
|
+
encoding: "utf-8",
|
|
4031
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
4032
|
+
});
|
|
4033
|
+
return output.split("\n").some((line) => line.trim() === windowName);
|
|
4034
|
+
} catch {
|
|
4035
|
+
return false;
|
|
4036
|
+
}
|
|
4037
|
+
}
|
|
4038
|
+
function joinAgentPane(windowName, widthPercent) {
|
|
4039
|
+
try {
|
|
4040
|
+
const paneId = execFileSync3(
|
|
4041
|
+
"tmux",
|
|
4042
|
+
[
|
|
4043
|
+
"join-pane",
|
|
4044
|
+
"-h",
|
|
4045
|
+
"-s",
|
|
4046
|
+
`${windowName}.0`,
|
|
4047
|
+
"-t",
|
|
4048
|
+
".",
|
|
4049
|
+
"-l",
|
|
4050
|
+
`${widthPercent}%`,
|
|
4051
|
+
"-P",
|
|
4052
|
+
"-F",
|
|
4053
|
+
"#{pane_id}"
|
|
4054
|
+
],
|
|
4055
|
+
{
|
|
4056
|
+
encoding: "utf-8",
|
|
4057
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
4058
|
+
}
|
|
4059
|
+
);
|
|
4060
|
+
return paneId.trim() || null;
|
|
4061
|
+
} catch {
|
|
4062
|
+
return null;
|
|
4063
|
+
}
|
|
4064
|
+
}
|
|
4065
|
+
function breakPane(paneId) {
|
|
4066
|
+
try {
|
|
4067
|
+
execFileSync3("tmux", ["break-pane", "-d", "-s", paneId], {
|
|
4068
|
+
stdio: "ignore"
|
|
4069
|
+
});
|
|
4070
|
+
} catch {
|
|
4071
|
+
}
|
|
4072
|
+
}
|
|
4073
|
+
function isPaneAlive(paneId) {
|
|
4074
|
+
try {
|
|
4075
|
+
const output = execFileSync3("tmux", ["list-panes", "-a", "-F", "#{pane_id}"], {
|
|
4076
|
+
encoding: "utf-8",
|
|
4077
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
4078
|
+
});
|
|
4079
|
+
return output.split("\n").some((line) => line.trim() === paneId);
|
|
4080
|
+
} catch {
|
|
4081
|
+
return false;
|
|
4082
|
+
}
|
|
4083
|
+
}
|
|
4084
|
+
function splitWithInfo(info, widthPercent) {
|
|
4085
|
+
try {
|
|
4086
|
+
const paneId = execFileSync3(
|
|
4087
|
+
"tmux",
|
|
4088
|
+
[
|
|
4089
|
+
"split-window",
|
|
4090
|
+
"-h",
|
|
4091
|
+
"-l",
|
|
4092
|
+
`${widthPercent}%`,
|
|
4093
|
+
"-d",
|
|
4094
|
+
"-P",
|
|
4095
|
+
"-F",
|
|
4096
|
+
"#{pane_id}",
|
|
4097
|
+
"sh",
|
|
4098
|
+
"-c",
|
|
4099
|
+
'printf "Issue: %s\\n\\nURL: %s\\n\\nNo Claude Code session active.\\nPress C to launch one.\\n" "$1" "$2"; read _',
|
|
4100
|
+
"--",
|
|
4101
|
+
info.title,
|
|
4102
|
+
info.url
|
|
4103
|
+
],
|
|
4104
|
+
{
|
|
4105
|
+
encoding: "utf-8",
|
|
4106
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
4107
|
+
}
|
|
4108
|
+
);
|
|
4109
|
+
return paneId.trim() || null;
|
|
4110
|
+
} catch {
|
|
4111
|
+
return null;
|
|
4112
|
+
}
|
|
4113
|
+
}
|
|
4114
|
+
function killPane(paneId) {
|
|
4115
|
+
try {
|
|
4116
|
+
execFileSync3("tmux", ["kill-pane", "-t", paneId], {
|
|
4117
|
+
stdio: "ignore"
|
|
4118
|
+
});
|
|
4119
|
+
} catch {
|
|
4120
|
+
}
|
|
4121
|
+
}
|
|
4122
|
+
var init_tmux_pane = __esm({
|
|
4123
|
+
"src/board/tmux-pane.ts"() {
|
|
4124
|
+
"use strict";
|
|
4125
|
+
}
|
|
4126
|
+
});
|
|
4127
|
+
|
|
4128
|
+
// src/board/hooks/use-zen-mode.ts
|
|
4129
|
+
import { useCallback as useCallback13, useEffect as useEffect5, useRef as useRef11, useState as useState7 } from "react";
|
|
4130
|
+
function findIssue(repos, selectedId) {
|
|
4131
|
+
if (!selectedId?.startsWith("gh:")) return null;
|
|
4132
|
+
for (const rd of repos) {
|
|
4133
|
+
for (const issue of rd.issues) {
|
|
4134
|
+
if (`gh:${rd.repo.name}:${issue.number}` === selectedId)
|
|
4135
|
+
return { issue, repoName: rd.repo.name };
|
|
4136
|
+
}
|
|
4137
|
+
}
|
|
4138
|
+
return null;
|
|
4139
|
+
}
|
|
4140
|
+
function cleanupPane(paneId, isAgent) {
|
|
4141
|
+
if (isAgent) {
|
|
4142
|
+
breakPane(paneId);
|
|
4143
|
+
} else {
|
|
4144
|
+
killPane(paneId);
|
|
4145
|
+
}
|
|
4146
|
+
}
|
|
4147
|
+
function openOrSplitPane(issue) {
|
|
4148
|
+
const winName = agentWindowName(issue.number);
|
|
4149
|
+
const hasAgent = windowExists(winName);
|
|
4150
|
+
if (hasAgent) {
|
|
4151
|
+
const paneId2 = joinAgentPane(winName, ZEN_PANE_WIDTH_PERCENT);
|
|
4152
|
+
return paneId2 ? { paneId: paneId2, isAgent: true } : null;
|
|
4153
|
+
}
|
|
4154
|
+
const paneId = splitWithInfo({ title: issue.title, url: issue.url }, ZEN_PANE_WIDTH_PERCENT);
|
|
4155
|
+
return paneId ? { paneId, isAgent: false } : null;
|
|
4156
|
+
}
|
|
4157
|
+
function useZenMode({
|
|
4158
|
+
ui,
|
|
4159
|
+
toast,
|
|
4160
|
+
termCols,
|
|
4161
|
+
repos,
|
|
4162
|
+
selectedId
|
|
4163
|
+
}) {
|
|
4164
|
+
const [zenPaneId, setZenPaneId] = useState7(null);
|
|
4165
|
+
const [zenIsAgentPane, setZenIsAgentPane] = useState7(false);
|
|
4166
|
+
const paneRef = useRef11({
|
|
4167
|
+
id: null,
|
|
4168
|
+
isAgent: false
|
|
4169
|
+
});
|
|
4170
|
+
paneRef.current = { id: zenPaneId, isAgent: zenIsAgentPane };
|
|
4171
|
+
const exitZen = useCallback13(() => {
|
|
4172
|
+
const { id, isAgent } = paneRef.current;
|
|
4173
|
+
if (id) {
|
|
4174
|
+
cleanupPane(id, isAgent);
|
|
4175
|
+
setZenPaneId(null);
|
|
4176
|
+
setZenIsAgentPane(false);
|
|
4177
|
+
}
|
|
4178
|
+
ui.exitZen();
|
|
4179
|
+
}, [ui]);
|
|
4180
|
+
const handleToggleZen = useCallback13(() => {
|
|
4181
|
+
if (ui.state.mode === "zen") {
|
|
4182
|
+
exitZen();
|
|
4183
|
+
return;
|
|
4184
|
+
}
|
|
4185
|
+
if (!process.env["TMUX"]) {
|
|
4186
|
+
toast.error("Zen mode requires tmux");
|
|
4187
|
+
return;
|
|
4188
|
+
}
|
|
4189
|
+
if (termCols < ZEN_MIN_COLS) {
|
|
4190
|
+
toast.error("Terminal too narrow for Zen mode");
|
|
4191
|
+
return;
|
|
4192
|
+
}
|
|
4193
|
+
const found = findIssue(repos, selectedId);
|
|
4194
|
+
const result = found ? openOrSplitPane(found.issue) : null;
|
|
4195
|
+
if (!result) {
|
|
4196
|
+
toast.error("Failed to create tmux pane");
|
|
4197
|
+
return;
|
|
4198
|
+
}
|
|
4199
|
+
setZenPaneId(result.paneId);
|
|
4200
|
+
setZenIsAgentPane(result.isAgent);
|
|
4201
|
+
ui.enterZen();
|
|
4202
|
+
}, [ui, toast, termCols, exitZen, repos, selectedId]);
|
|
4203
|
+
const swapToAgent = useCallback13(
|
|
4204
|
+
(issueNumber) => {
|
|
4205
|
+
const { id, isAgent } = paneRef.current;
|
|
4206
|
+
if (ui.state.mode !== "zen" || !id) return;
|
|
4207
|
+
cleanupPane(id, isAgent);
|
|
4208
|
+
setTimeout(() => {
|
|
4209
|
+
const winName = agentWindowName(issueNumber);
|
|
4210
|
+
if (windowExists(winName)) {
|
|
4211
|
+
const newPaneId = joinAgentPane(winName, ZEN_PANE_WIDTH_PERCENT);
|
|
4212
|
+
setZenPaneId(newPaneId);
|
|
4213
|
+
setZenIsAgentPane(true);
|
|
4214
|
+
}
|
|
4215
|
+
}, 500);
|
|
4216
|
+
},
|
|
4217
|
+
[ui.state.mode]
|
|
4218
|
+
);
|
|
4219
|
+
const prevSelectedRef = useRef11(null);
|
|
4220
|
+
useEffect5(() => {
|
|
4221
|
+
if (ui.state.mode !== "zen" || !zenPaneId) {
|
|
4222
|
+
prevSelectedRef.current = selectedId;
|
|
4223
|
+
return;
|
|
4224
|
+
}
|
|
4225
|
+
if (selectedId === prevSelectedRef.current) return;
|
|
4226
|
+
prevSelectedRef.current = selectedId;
|
|
4227
|
+
const timer = setTimeout(() => {
|
|
4228
|
+
const { id, isAgent } = paneRef.current;
|
|
4229
|
+
if (!id) return;
|
|
4230
|
+
const found = findIssue(repos, selectedId);
|
|
4231
|
+
if (!found) return;
|
|
4232
|
+
cleanupPane(id, isAgent);
|
|
4233
|
+
const result = openOrSplitPane(found.issue);
|
|
4234
|
+
if (!result) {
|
|
4235
|
+
setZenPaneId(null);
|
|
4236
|
+
setZenIsAgentPane(false);
|
|
4237
|
+
ui.exitZen();
|
|
4238
|
+
toast.error("Zen pane lost \u2014 exiting zen mode");
|
|
4239
|
+
return;
|
|
4240
|
+
}
|
|
4241
|
+
setZenPaneId(result.paneId);
|
|
4242
|
+
setZenIsAgentPane(result.isAgent);
|
|
4243
|
+
}, CURSOR_FOLLOW_DEBOUNCE_MS);
|
|
4244
|
+
return () => clearTimeout(timer);
|
|
4245
|
+
}, [ui.state.mode, zenPaneId, selectedId, repos, ui, toast]);
|
|
4246
|
+
useEffect5(() => {
|
|
4247
|
+
if (ui.state.mode !== "zen" || !zenPaneId) return;
|
|
4248
|
+
const interval = setInterval(() => {
|
|
4249
|
+
if (!isPaneAlive(zenPaneId)) {
|
|
4250
|
+
exitZen();
|
|
4251
|
+
toast.info("Zen pane closed");
|
|
4252
|
+
}
|
|
4253
|
+
}, DEAD_PANE_CHECK_MS);
|
|
4254
|
+
return () => clearInterval(interval);
|
|
4255
|
+
}, [ui.state.mode, zenPaneId, exitZen, toast]);
|
|
4256
|
+
return { zenPaneId, zenIsAgentPane, handleToggleZen, swapToAgent };
|
|
4257
|
+
}
|
|
4258
|
+
var ZEN_PANE_WIDTH_PERCENT, ZEN_MIN_COLS, CURSOR_FOLLOW_DEBOUNCE_MS, DEAD_PANE_CHECK_MS;
|
|
4259
|
+
var init_use_zen_mode = __esm({
|
|
4260
|
+
"src/board/hooks/use-zen-mode.ts"() {
|
|
4261
|
+
"use strict";
|
|
4262
|
+
init_tmux_pane();
|
|
4263
|
+
ZEN_PANE_WIDTH_PERCENT = 65;
|
|
4264
|
+
ZEN_MIN_COLS = 100;
|
|
4265
|
+
CURSOR_FOLLOW_DEBOUNCE_MS = 150;
|
|
4266
|
+
DEAD_PANE_CHECK_MS = 2e3;
|
|
4267
|
+
}
|
|
4268
|
+
});
|
|
4269
|
+
|
|
3974
4270
|
// src/board/components/action-log.tsx
|
|
3975
4271
|
import { Box, Text } from "ink";
|
|
3976
|
-
import { useEffect as
|
|
4272
|
+
import { useEffect as useEffect6, useState as useState8 } from "react";
|
|
3977
4273
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3978
4274
|
function relativeTime(ago) {
|
|
3979
4275
|
const seconds = Math.floor((Date.now() - ago) / 1e3);
|
|
@@ -3994,8 +4290,8 @@ function statusColor(status) {
|
|
|
3994
4290
|
return "yellow";
|
|
3995
4291
|
}
|
|
3996
4292
|
function ActionLog({ entries }) {
|
|
3997
|
-
const [, setTick] =
|
|
3998
|
-
|
|
4293
|
+
const [, setTick] = useState8(0);
|
|
4294
|
+
useEffect6(() => {
|
|
3999
4295
|
const id = setInterval(() => setTick((t) => t + 1), 5e3);
|
|
4000
4296
|
return () => clearInterval(id);
|
|
4001
4297
|
}, []);
|
|
@@ -4159,7 +4455,7 @@ var init_agent_activity_panel = __esm({
|
|
|
4159
4455
|
|
|
4160
4456
|
// src/board/components/detail-panel.tsx
|
|
4161
4457
|
import { Box as Box5, Text as Text5 } from "ink";
|
|
4162
|
-
import { useEffect as
|
|
4458
|
+
import { useEffect as useEffect7 } from "react";
|
|
4163
4459
|
import { Fragment, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
4164
4460
|
function stripMarkdown(text) {
|
|
4165
4461
|
return text.replace(/^#{1,6}\s+/gm, "").replace(/\*\*(.+?)\*\*/g, "$1").replace(/\*(.+?)\*/g, "$1").replace(/__(.+?)__/g, "$1").replace(/_(.+?)_/g, "$1").replace(/~~(.+?)~~/g, "$1").replace(/`{1,3}[^`]*`{1,3}/g, (m) => m.replace(/`/g, "")).replace(/^\s*[-*+]\s+/gm, " - ").replace(/^\s*\d+\.\s+/gm, " ").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/!\[([^\]]*)\]\([^)]+\)/g, "[$1]").replace(/^>\s+/gm, " ").replace(/---+/g, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
@@ -4211,7 +4507,7 @@ function DetailPanel({
|
|
|
4211
4507
|
fetchComments,
|
|
4212
4508
|
issueRepo
|
|
4213
4509
|
}) {
|
|
4214
|
-
|
|
4510
|
+
useEffect7(() => {
|
|
4215
4511
|
if (!(issue && fetchComments && issueRepo)) return;
|
|
4216
4512
|
if (commentsState !== null && commentsState !== void 0) return;
|
|
4217
4513
|
fetchComments(issueRepo, issue.number);
|
|
@@ -4310,6 +4606,12 @@ function HintBar({
|
|
|
4310
4606
|
/* @__PURE__ */ jsx6(Text6, { color: "gray", children: " Space:toggle Enter:actions Esc:cancel" })
|
|
4311
4607
|
] });
|
|
4312
4608
|
}
|
|
4609
|
+
if (uiMode === "zen") {
|
|
4610
|
+
return /* @__PURE__ */ jsxs6(Box6, { children: [
|
|
4611
|
+
/* @__PURE__ */ jsx6(Text6, { color: "green", bold: true, children: "[ZEN]" }),
|
|
4612
|
+
/* @__PURE__ */ jsx6(Text6, { color: "gray", children: " j/k:nav C:claude Z/Esc:exit q:quit" })
|
|
4613
|
+
] });
|
|
4614
|
+
}
|
|
4313
4615
|
if (uiMode === "focus") {
|
|
4314
4616
|
return /* @__PURE__ */ jsx6(Box6, { children: /* @__PURE__ */ jsx6(Text6, { color: "magenta", bold: true, children: "[FOCUS] Focus mode \u2014 Esc to exit" }) });
|
|
4315
4617
|
}
|
|
@@ -4340,7 +4642,7 @@ function HintBar({
|
|
|
4340
4642
|
0: "j/k:scroll Esc:close ? help",
|
|
4341
4643
|
1: "j/k:move Enter:filter 0-4:panel ? help",
|
|
4342
4644
|
2: "j/k:move Enter:filter Esc:clear 0-4:panel ? help",
|
|
4343
|
-
3: `j/k:move Enter:detail g:open p:pick m:status c:comment C:claude /:search n:new 0-4:panel${hasUndoable ? " u:undo" : ""} ? help q:quit`,
|
|
4645
|
+
3: `j/k:move Enter:detail g:open p:pick m:status c:comment C:claude /:search n:new H:hide-panel Z:zen 0-4:panel${hasUndoable ? " u:undo" : ""} ? help q:quit`,
|
|
4344
4646
|
4: "j/k:scroll Enter:jump r:refresh 0-4:panel ? help"
|
|
4345
4647
|
};
|
|
4346
4648
|
return /* @__PURE__ */ jsxs6(Box6, { children: [
|
|
@@ -4361,7 +4663,7 @@ var init_hint_bar = __esm({
|
|
|
4361
4663
|
|
|
4362
4664
|
// src/board/components/bulk-action-menu.tsx
|
|
4363
4665
|
import { Box as Box7, Text as Text7, useInput as useInput2 } from "ink";
|
|
4364
|
-
import { useState as
|
|
4666
|
+
import { useState as useState9 } from "react";
|
|
4365
4667
|
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
4366
4668
|
function getMenuItems(selectionType) {
|
|
4367
4669
|
if (selectionType === "github") {
|
|
@@ -4375,7 +4677,7 @@ function getMenuItems(selectionType) {
|
|
|
4375
4677
|
}
|
|
4376
4678
|
function BulkActionMenu({ count, selectionType, onSelect, onCancel }) {
|
|
4377
4679
|
const items = getMenuItems(selectionType);
|
|
4378
|
-
const [selectedIdx, setSelectedIdx] =
|
|
4680
|
+
const [selectedIdx, setSelectedIdx] = useState9(0);
|
|
4379
4681
|
useInput2((input2, key) => {
|
|
4380
4682
|
if (key.escape) return onCancel();
|
|
4381
4683
|
if (key.return) {
|
|
@@ -4478,7 +4780,7 @@ import { tmpdir } from "os";
|
|
|
4478
4780
|
import { join as join5 } from "path";
|
|
4479
4781
|
import { TextInput } from "@inkjs/ui";
|
|
4480
4782
|
import { Box as Box8, Text as Text8, useInput as useInput3, useStdin } from "ink";
|
|
4481
|
-
import { useEffect as
|
|
4783
|
+
import { useEffect as useEffect8, useRef as useRef12, useState as useState10 } from "react";
|
|
4482
4784
|
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
4483
4785
|
function CommentInput({
|
|
4484
4786
|
issueNumber,
|
|
@@ -4487,13 +4789,13 @@ function CommentInput({
|
|
|
4487
4789
|
onPauseRefresh,
|
|
4488
4790
|
onResumeRefresh
|
|
4489
4791
|
}) {
|
|
4490
|
-
const [value, setValue] =
|
|
4491
|
-
const [editing, setEditing] =
|
|
4792
|
+
const [value, setValue] = useState10("");
|
|
4793
|
+
const [editing, setEditing] = useState10(false);
|
|
4492
4794
|
const { setRawMode } = useStdin();
|
|
4493
|
-
const onSubmitRef =
|
|
4494
|
-
const onCancelRef =
|
|
4495
|
-
const onPauseRef =
|
|
4496
|
-
const onResumeRef =
|
|
4795
|
+
const onSubmitRef = useRef12(onSubmit);
|
|
4796
|
+
const onCancelRef = useRef12(onCancel);
|
|
4797
|
+
const onPauseRef = useRef12(onPauseRefresh);
|
|
4798
|
+
const onResumeRef = useRef12(onResumeRefresh);
|
|
4497
4799
|
onSubmitRef.current = onSubmit;
|
|
4498
4800
|
onCancelRef.current = onCancel;
|
|
4499
4801
|
onPauseRef.current = onPauseRefresh;
|
|
@@ -4508,7 +4810,7 @@ function CommentInput({
|
|
|
4508
4810
|
setEditing(true);
|
|
4509
4811
|
}
|
|
4510
4812
|
});
|
|
4511
|
-
|
|
4813
|
+
useEffect8(() => {
|
|
4512
4814
|
if (!editing) return;
|
|
4513
4815
|
const editor = resolveEditor();
|
|
4514
4816
|
if (!editor) {
|
|
@@ -4601,7 +4903,7 @@ var init_confirm_prompt = __esm({
|
|
|
4601
4903
|
// src/board/components/label-picker.tsx
|
|
4602
4904
|
import { Spinner } from "@inkjs/ui";
|
|
4603
4905
|
import { Box as Box10, Text as Text10, useInput as useInput5 } from "ink";
|
|
4604
|
-
import { useEffect as
|
|
4906
|
+
import { useEffect as useEffect9, useRef as useRef13, useState as useState11 } from "react";
|
|
4605
4907
|
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
4606
4908
|
function LabelPicker({
|
|
4607
4909
|
repo,
|
|
@@ -4611,13 +4913,13 @@ function LabelPicker({
|
|
|
4611
4913
|
onCancel,
|
|
4612
4914
|
onError
|
|
4613
4915
|
}) {
|
|
4614
|
-
const [labels, setLabels] =
|
|
4615
|
-
const [loading, setLoading] =
|
|
4616
|
-
const [fetchAttempted, setFetchAttempted] =
|
|
4617
|
-
const [selected, setSelected] =
|
|
4618
|
-
const [cursor, setCursor] =
|
|
4619
|
-
const submittedRef =
|
|
4620
|
-
|
|
4916
|
+
const [labels, setLabels] = useState11(labelCache[repo] ?? null);
|
|
4917
|
+
const [loading, setLoading] = useState11(labels === null);
|
|
4918
|
+
const [fetchAttempted, setFetchAttempted] = useState11(false);
|
|
4919
|
+
const [selected, setSelected] = useState11(new Set(currentLabels));
|
|
4920
|
+
const [cursor, setCursor] = useState11(0);
|
|
4921
|
+
const submittedRef = useRef13(false);
|
|
4922
|
+
useEffect9(() => {
|
|
4621
4923
|
if (labels !== null || fetchAttempted) return;
|
|
4622
4924
|
setFetchAttempted(true);
|
|
4623
4925
|
setLoading(true);
|
|
@@ -4720,7 +5022,7 @@ var init_label_picker = __esm({
|
|
|
4720
5022
|
// src/board/components/create-issue-form.tsx
|
|
4721
5023
|
import { TextInput as TextInput2 } from "@inkjs/ui";
|
|
4722
5024
|
import { Box as Box11, Text as Text11, useInput as useInput6 } from "ink";
|
|
4723
|
-
import { useState as
|
|
5025
|
+
import { useState as useState12 } from "react";
|
|
4724
5026
|
import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
4725
5027
|
function CreateIssueForm({
|
|
4726
5028
|
repos,
|
|
@@ -4733,9 +5035,9 @@ function CreateIssueForm({
|
|
|
4733
5035
|
0,
|
|
4734
5036
|
repos.findIndex((r) => r.name === defaultRepo)
|
|
4735
5037
|
) : 0;
|
|
4736
|
-
const [repoIdx, setRepoIdx] =
|
|
4737
|
-
const [title, setTitle] =
|
|
4738
|
-
const [field, setField] =
|
|
5038
|
+
const [repoIdx, setRepoIdx] = useState12(defaultRepoIdx);
|
|
5039
|
+
const [title, setTitle] = useState12("");
|
|
5040
|
+
const [field, setField] = useState12("title");
|
|
4739
5041
|
useInput6((input2, key) => {
|
|
4740
5042
|
if (field === "labels") return;
|
|
4741
5043
|
if (key.escape) return onCancel();
|
|
@@ -4837,7 +5139,7 @@ import { mkdtempSync as mkdtempSync2, readFileSync as readFileSync7, rmSync as r
|
|
|
4837
5139
|
import { tmpdir as tmpdir2 } from "os";
|
|
4838
5140
|
import { join as join6 } from "path";
|
|
4839
5141
|
import { Box as Box12, Text as Text12, useStdin as useStdin2 } from "ink";
|
|
4840
|
-
import { useEffect as
|
|
5142
|
+
import { useEffect as useEffect10, useRef as useRef14, useState as useState13 } from "react";
|
|
4841
5143
|
import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
4842
5144
|
function buildEditorFile(issue, repoName, statusOptions, repoLabels) {
|
|
4843
5145
|
const statusNames = statusOptions.map((o) => o.name).join(", ");
|
|
@@ -4921,15 +5223,15 @@ function EditIssueOverlay({
|
|
|
4921
5223
|
onToastError,
|
|
4922
5224
|
onPushEntry
|
|
4923
5225
|
}) {
|
|
4924
|
-
const [editing, setEditing] =
|
|
5226
|
+
const [editing, setEditing] = useState13(true);
|
|
4925
5227
|
const { setRawMode } = useStdin2();
|
|
4926
|
-
const onDoneRef =
|
|
4927
|
-
const onPauseRef =
|
|
4928
|
-
const onResumeRef =
|
|
5228
|
+
const onDoneRef = useRef14(onDone);
|
|
5229
|
+
const onPauseRef = useRef14(onPauseRefresh);
|
|
5230
|
+
const onResumeRef = useRef14(onResumeRefresh);
|
|
4929
5231
|
onDoneRef.current = onDone;
|
|
4930
5232
|
onPauseRef.current = onPauseRefresh;
|
|
4931
5233
|
onResumeRef.current = onResumeRefresh;
|
|
4932
|
-
|
|
5234
|
+
useEffect10(() => {
|
|
4933
5235
|
if (!editing) return;
|
|
4934
5236
|
const editor = resolveEditor();
|
|
4935
5237
|
if (!editor) {
|
|
@@ -5097,7 +5399,7 @@ var init_edit_issue_overlay = __esm({
|
|
|
5097
5399
|
|
|
5098
5400
|
// src/board/components/focus-mode.tsx
|
|
5099
5401
|
import { Box as Box13, Text as Text13, useInput as useInput7 } from "ink";
|
|
5100
|
-
import { useCallback as
|
|
5402
|
+
import { useCallback as useCallback14, useEffect as useEffect11, useRef as useRef15, useState as useState14 } from "react";
|
|
5101
5403
|
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
5102
5404
|
function formatTime(secs) {
|
|
5103
5405
|
const m = Math.floor(secs / 60);
|
|
@@ -5105,10 +5407,10 @@ function formatTime(secs) {
|
|
|
5105
5407
|
return `${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
|
|
5106
5408
|
}
|
|
5107
5409
|
function FocusMode({ label, durationSec, onExit, onEndAction }) {
|
|
5108
|
-
const [remaining, setRemaining] =
|
|
5109
|
-
const [timerDone, setTimerDone] =
|
|
5110
|
-
const bellSentRef =
|
|
5111
|
-
|
|
5410
|
+
const [remaining, setRemaining] = useState14(durationSec);
|
|
5411
|
+
const [timerDone, setTimerDone] = useState14(false);
|
|
5412
|
+
const bellSentRef = useRef15(false);
|
|
5413
|
+
useEffect11(() => {
|
|
5112
5414
|
if (timerDone) return;
|
|
5113
5415
|
const interval = setInterval(() => {
|
|
5114
5416
|
setRemaining((prev) => {
|
|
@@ -5122,13 +5424,13 @@ function FocusMode({ label, durationSec, onExit, onEndAction }) {
|
|
|
5122
5424
|
}, 1e3);
|
|
5123
5425
|
return () => clearInterval(interval);
|
|
5124
5426
|
}, [timerDone]);
|
|
5125
|
-
|
|
5427
|
+
useEffect11(() => {
|
|
5126
5428
|
if (timerDone && !bellSentRef.current) {
|
|
5127
5429
|
bellSentRef.current = true;
|
|
5128
5430
|
process.stdout.write("\x07");
|
|
5129
5431
|
}
|
|
5130
5432
|
}, [timerDone]);
|
|
5131
|
-
const handleInput =
|
|
5433
|
+
const handleInput = useCallback14(
|
|
5132
5434
|
(input2, key) => {
|
|
5133
5435
|
if (key.escape) {
|
|
5134
5436
|
if (timerDone) {
|
|
@@ -5206,7 +5508,7 @@ var init_focus_mode = __esm({
|
|
|
5206
5508
|
import { TextInput as TextInput3 } from "@inkjs/ui";
|
|
5207
5509
|
import { Fzf } from "fzf";
|
|
5208
5510
|
import { Box as Box14, Text as Text14, useInput as useInput8 } from "ink";
|
|
5209
|
-
import { useMemo as useMemo4, useState as
|
|
5511
|
+
import { useMemo as useMemo4, useState as useState15 } from "react";
|
|
5210
5512
|
import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
5211
5513
|
function keepCursorVisible(cursor, offset, visible) {
|
|
5212
5514
|
if (cursor < offset) return cursor;
|
|
@@ -5214,9 +5516,9 @@ function keepCursorVisible(cursor, offset, visible) {
|
|
|
5214
5516
|
return offset;
|
|
5215
5517
|
}
|
|
5216
5518
|
function FuzzyPicker({ repos, onSelect, onClose }) {
|
|
5217
|
-
const [query, setQuery] =
|
|
5218
|
-
const [cursor, setCursor] =
|
|
5219
|
-
const [scrollOffset, setScrollOffset] =
|
|
5519
|
+
const [query, setQuery] = useState15("");
|
|
5520
|
+
const [cursor, setCursor] = useState15(0);
|
|
5521
|
+
const [scrollOffset, setScrollOffset] = useState15(0);
|
|
5220
5522
|
const allIssues = useMemo4(() => {
|
|
5221
5523
|
const items = [];
|
|
5222
5524
|
for (const rd of repos) {
|
|
@@ -5437,6 +5739,8 @@ var init_help_overlay = __esm({
|
|
|
5437
5739
|
{ key: "F", desc: "Fuzzy find issue (telescope-style)" },
|
|
5438
5740
|
{ key: "t", desc: "Toggle @me filter (my issues only)" },
|
|
5439
5741
|
{ key: "f", desc: "Focus mode" },
|
|
5742
|
+
{ key: "Z", desc: "Zen mode (tmux split with Claude Code)" },
|
|
5743
|
+
{ key: "H", desc: "Toggle left panel (repos/statuses)" },
|
|
5440
5744
|
{ key: "?", desc: "Toggle help" },
|
|
5441
5745
|
{ key: "Esc", desc: "Close overlay / Back to normal" }
|
|
5442
5746
|
]
|
|
@@ -5480,7 +5784,7 @@ import { tmpdir as tmpdir3 } from "os";
|
|
|
5480
5784
|
import { join as join7 } from "path";
|
|
5481
5785
|
import { Spinner as Spinner2, TextInput as TextInput4 } from "@inkjs/ui";
|
|
5482
5786
|
import { Box as Box16, Text as Text16, useInput as useInput10, useStdin as useStdin3 } from "ink";
|
|
5483
|
-
import { useCallback as
|
|
5787
|
+
import { useCallback as useCallback15, useEffect as useEffect12, useRef as useRef16, useState as useState16 } from "react";
|
|
5484
5788
|
import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
5485
5789
|
function NlCreateOverlay({
|
|
5486
5790
|
repos,
|
|
@@ -5492,19 +5796,19 @@ function NlCreateOverlay({
|
|
|
5492
5796
|
onResumeRefresh,
|
|
5493
5797
|
onLlmFallback
|
|
5494
5798
|
}) {
|
|
5495
|
-
const [, setInput] =
|
|
5496
|
-
const [isParsing, setIsParsing] =
|
|
5497
|
-
const [parsed, setParsed] =
|
|
5498
|
-
const [parseError, setParseError] =
|
|
5499
|
-
const [step, setStep] =
|
|
5500
|
-
const [body, setBody] =
|
|
5501
|
-
const [editingBody, setEditingBody] =
|
|
5502
|
-
const submittedRef =
|
|
5503
|
-
const parseParamsRef =
|
|
5504
|
-
const onSubmitRef =
|
|
5505
|
-
const onCancelRef =
|
|
5506
|
-
const onPauseRef =
|
|
5507
|
-
const onResumeRef =
|
|
5799
|
+
const [, setInput] = useState16("");
|
|
5800
|
+
const [isParsing, setIsParsing] = useState16(false);
|
|
5801
|
+
const [parsed, setParsed] = useState16(null);
|
|
5802
|
+
const [parseError, setParseError] = useState16(null);
|
|
5803
|
+
const [step, setStep] = useState16("input");
|
|
5804
|
+
const [body, setBody] = useState16("");
|
|
5805
|
+
const [editingBody, setEditingBody] = useState16(false);
|
|
5806
|
+
const submittedRef = useRef16(false);
|
|
5807
|
+
const parseParamsRef = useRef16(null);
|
|
5808
|
+
const onSubmitRef = useRef16(onSubmit);
|
|
5809
|
+
const onCancelRef = useRef16(onCancel);
|
|
5810
|
+
const onPauseRef = useRef16(onPauseRefresh);
|
|
5811
|
+
const onResumeRef = useRef16(onResumeRefresh);
|
|
5508
5812
|
onSubmitRef.current = onSubmit;
|
|
5509
5813
|
onCancelRef.current = onCancel;
|
|
5510
5814
|
onPauseRef.current = onPauseRefresh;
|
|
@@ -5514,7 +5818,7 @@ function NlCreateOverlay({
|
|
|
5514
5818
|
0,
|
|
5515
5819
|
repos.findIndex((r) => r.name === defaultRepoName)
|
|
5516
5820
|
) : 0;
|
|
5517
|
-
const [repoIdx, setRepoIdx] =
|
|
5821
|
+
const [repoIdx, setRepoIdx] = useState16(defaultRepoIdx);
|
|
5518
5822
|
const selectedRepo = repos[repoIdx];
|
|
5519
5823
|
useInput10((inputChar, key) => {
|
|
5520
5824
|
if (isParsing || editingBody) return;
|
|
@@ -5541,7 +5845,7 @@ function NlCreateOverlay({
|
|
|
5541
5845
|
setEditingBody(true);
|
|
5542
5846
|
}
|
|
5543
5847
|
});
|
|
5544
|
-
|
|
5848
|
+
useEffect12(() => {
|
|
5545
5849
|
if (!editingBody) return;
|
|
5546
5850
|
const editor = resolveEditor();
|
|
5547
5851
|
if (!editor) {
|
|
@@ -5573,7 +5877,7 @@ function NlCreateOverlay({
|
|
|
5573
5877
|
setEditingBody(false);
|
|
5574
5878
|
}
|
|
5575
5879
|
}, [editingBody, body, setRawMode]);
|
|
5576
|
-
const handleInputSubmit =
|
|
5880
|
+
const handleInputSubmit = useCallback15(
|
|
5577
5881
|
(text) => {
|
|
5578
5882
|
const trimmed = text.trim();
|
|
5579
5883
|
if (!trimmed) return;
|
|
@@ -5585,7 +5889,7 @@ function NlCreateOverlay({
|
|
|
5585
5889
|
},
|
|
5586
5890
|
[selectedRepo, labelCache]
|
|
5587
5891
|
);
|
|
5588
|
-
|
|
5892
|
+
useEffect12(() => {
|
|
5589
5893
|
if (!(isParsing && parseParamsRef.current)) return;
|
|
5590
5894
|
const { input: capturedInput, validLabels } = parseParamsRef.current;
|
|
5591
5895
|
extractIssueFields(capturedInput, {
|
|
@@ -5717,10 +6021,10 @@ var init_nl_create_overlay = __esm({
|
|
|
5717
6021
|
|
|
5718
6022
|
// src/board/components/nudge-overlay.tsx
|
|
5719
6023
|
import { Box as Box17, Text as Text17, useInput as useInput11 } from "ink";
|
|
5720
|
-
import { useState as
|
|
6024
|
+
import { useState as useState17 } from "react";
|
|
5721
6025
|
import { jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
5722
6026
|
function NudgeOverlay({ candidates, onAction, onCancel }) {
|
|
5723
|
-
const [selectedIdx, setSelectedIdx] =
|
|
6027
|
+
const [selectedIdx, setSelectedIdx] = useState17(0);
|
|
5724
6028
|
useInput11((input2, key) => {
|
|
5725
6029
|
if (key.escape) {
|
|
5726
6030
|
onAction({ type: "dismiss" });
|
|
@@ -5841,7 +6145,7 @@ var init_search_bar = __esm({
|
|
|
5841
6145
|
|
|
5842
6146
|
// src/board/components/status-picker.tsx
|
|
5843
6147
|
import { Box as Box19, Text as Text19, useInput as useInput12 } from "ink";
|
|
5844
|
-
import { useRef as
|
|
6148
|
+
import { useRef as useRef17, useState as useState18 } from "react";
|
|
5845
6149
|
import { jsx as jsx19, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
5846
6150
|
function isTerminal(name) {
|
|
5847
6151
|
return TERMINAL_STATUS_RE.test(name);
|
|
@@ -5889,12 +6193,12 @@ function StatusPicker({
|
|
|
5889
6193
|
onCancel,
|
|
5890
6194
|
showTerminalStatuses = true
|
|
5891
6195
|
}) {
|
|
5892
|
-
const [selectedIdx, setSelectedIdx] =
|
|
6196
|
+
const [selectedIdx, setSelectedIdx] = useState18(() => {
|
|
5893
6197
|
const idx = options.findIndex((o) => o.name === currentStatus);
|
|
5894
6198
|
return idx >= 0 ? idx : 0;
|
|
5895
6199
|
});
|
|
5896
|
-
const [confirmingTerminal, setConfirmingTerminal] =
|
|
5897
|
-
const submittedRef =
|
|
6200
|
+
const [confirmingTerminal, setConfirmingTerminal] = useState18(false);
|
|
6201
|
+
const submittedRef = useRef17(false);
|
|
5898
6202
|
useInput12((input2, key) => {
|
|
5899
6203
|
if (confirmingTerminal) {
|
|
5900
6204
|
handleConfirmInput(input2, key, {
|
|
@@ -5962,12 +6266,12 @@ var init_status_picker = __esm({
|
|
|
5962
6266
|
|
|
5963
6267
|
// src/board/components/triage-overlay.tsx
|
|
5964
6268
|
import { Box as Box20, Text as Text20, useInput as useInput13 } from "ink";
|
|
5965
|
-
import { useState as
|
|
6269
|
+
import { useState as useState19 } from "react";
|
|
5966
6270
|
import { jsx as jsx20, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
5967
6271
|
function TriageOverlay({ candidates, phases, onAction, onCancel }) {
|
|
5968
|
-
const [selected, setSelected] =
|
|
5969
|
-
const [cursorIdx, setCursorIdx] =
|
|
5970
|
-
const [phaseIdx, setPhaseIdx] =
|
|
6272
|
+
const [selected, setSelected] = useState19(() => /* @__PURE__ */ new Set());
|
|
6273
|
+
const [cursorIdx, setCursorIdx] = useState19(0);
|
|
6274
|
+
const [phaseIdx, setPhaseIdx] = useState19(0);
|
|
5971
6275
|
useInput13((input2, key) => {
|
|
5972
6276
|
if (key.escape) {
|
|
5973
6277
|
onCancel();
|
|
@@ -6105,7 +6409,7 @@ var init_triage_overlay = __esm({
|
|
|
6105
6409
|
|
|
6106
6410
|
// src/board/components/workflow-overlay.tsx
|
|
6107
6411
|
import { Box as Box21, Text as Text21, useInput as useInput14 } from "ink";
|
|
6108
|
-
import { useState as
|
|
6412
|
+
import { useState as useState20 } from "react";
|
|
6109
6413
|
import { jsx as jsx21, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
6110
6414
|
function phaseIcon(state) {
|
|
6111
6415
|
switch (state) {
|
|
@@ -6135,7 +6439,7 @@ function WorkflowOverlay({
|
|
|
6135
6439
|
onAction,
|
|
6136
6440
|
onCancel
|
|
6137
6441
|
}) {
|
|
6138
|
-
const [selectedIdx, setSelectedIdx] =
|
|
6442
|
+
const [selectedIdx, setSelectedIdx] = useState20(0);
|
|
6139
6443
|
useInput14((input2, key) => {
|
|
6140
6444
|
if (key.escape) {
|
|
6141
6445
|
onCancel();
|
|
@@ -6413,7 +6717,7 @@ var init_overlay_renderer = __esm({
|
|
|
6413
6717
|
|
|
6414
6718
|
// src/board/components/panel-layout.tsx
|
|
6415
6719
|
import { Box as Box22 } from "ink";
|
|
6416
|
-
import { jsx as jsx23, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
6720
|
+
import { Fragment as Fragment3, jsx as jsx23, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
6417
6721
|
function getLayoutMode(cols) {
|
|
6418
6722
|
if (cols >= WIDE_THRESHOLD) return "wide";
|
|
6419
6723
|
if (cols >= MEDIUM_THRESHOLD) return "medium";
|
|
@@ -6429,17 +6733,18 @@ function PanelLayout({
|
|
|
6429
6733
|
statusesPanel,
|
|
6430
6734
|
issuesPanel,
|
|
6431
6735
|
detailPanel,
|
|
6432
|
-
activityPanel
|
|
6736
|
+
activityPanel,
|
|
6737
|
+
hideLeftPanel
|
|
6433
6738
|
}) {
|
|
6434
6739
|
const mode = getLayoutMode(cols);
|
|
6435
6740
|
if (mode === "wide") {
|
|
6436
6741
|
const detailWidth = getDetailWidth(cols);
|
|
6437
6742
|
return /* @__PURE__ */ jsxs23(Box22, { flexDirection: "column", children: [
|
|
6438
6743
|
/* @__PURE__ */ jsxs23(Box22, { height: issuesPanelHeight, children: [
|
|
6439
|
-
/* @__PURE__ */ jsxs23(Box22, { flexDirection: "column", width: LEFT_COL_WIDTH, children: [
|
|
6744
|
+
!hideLeftPanel ? /* @__PURE__ */ jsxs23(Box22, { flexDirection: "column", width: LEFT_COL_WIDTH, children: [
|
|
6440
6745
|
reposPanel,
|
|
6441
6746
|
statusesPanel
|
|
6442
|
-
] }),
|
|
6747
|
+
] }) : null,
|
|
6443
6748
|
/* @__PURE__ */ jsx23(Box22, { flexGrow: 1, flexDirection: "column", children: issuesPanel }),
|
|
6444
6749
|
/* @__PURE__ */ jsx23(Box22, { width: detailWidth, flexDirection: "column", children: detailPanel })
|
|
6445
6750
|
] }),
|
|
@@ -6449,18 +6754,20 @@ function PanelLayout({
|
|
|
6449
6754
|
if (mode === "medium") {
|
|
6450
6755
|
return /* @__PURE__ */ jsxs23(Box22, { flexDirection: "column", children: [
|
|
6451
6756
|
/* @__PURE__ */ jsxs23(Box22, { height: issuesPanelHeight, children: [
|
|
6452
|
-
/* @__PURE__ */ jsxs23(Box22, { flexDirection: "column", width: LEFT_COL_WIDTH, children: [
|
|
6757
|
+
!hideLeftPanel ? /* @__PURE__ */ jsxs23(Box22, { flexDirection: "column", width: LEFT_COL_WIDTH, children: [
|
|
6453
6758
|
reposPanel,
|
|
6454
6759
|
statusesPanel
|
|
6455
|
-
] }),
|
|
6760
|
+
] }) : null,
|
|
6456
6761
|
/* @__PURE__ */ jsx23(Box22, { flexGrow: 1, flexDirection: "column", children: issuesPanel })
|
|
6457
6762
|
] }),
|
|
6458
6763
|
/* @__PURE__ */ jsx23(Box22, { height: ACTIVITY_HEIGHT, children: activityPanel })
|
|
6459
6764
|
] });
|
|
6460
6765
|
}
|
|
6461
6766
|
return /* @__PURE__ */ jsxs23(Box22, { flexDirection: "column", children: [
|
|
6462
|
-
|
|
6463
|
-
|
|
6767
|
+
!hideLeftPanel ? /* @__PURE__ */ jsxs23(Fragment3, { children: [
|
|
6768
|
+
reposPanel,
|
|
6769
|
+
statusesPanel
|
|
6770
|
+
] }) : null,
|
|
6464
6771
|
/* @__PURE__ */ jsx23(Box22, { flexGrow: 1, flexDirection: "column", children: issuesPanel }),
|
|
6465
6772
|
/* @__PURE__ */ jsx23(Box22, { height: ACTIVITY_HEIGHT, children: activityPanel })
|
|
6466
6773
|
] });
|
|
@@ -6806,10 +7113,10 @@ var init_statuses_panel = __esm({
|
|
|
6806
7113
|
// src/board/components/toast-container.tsx
|
|
6807
7114
|
import { Spinner as Spinner3 } from "@inkjs/ui";
|
|
6808
7115
|
import { Box as Box27, Text as Text26 } from "ink";
|
|
6809
|
-
import { Fragment as
|
|
7116
|
+
import { Fragment as Fragment4, jsx as jsx28, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
6810
7117
|
function ToastContainer({ toasts }) {
|
|
6811
7118
|
if (toasts.length === 0) return null;
|
|
6812
|
-
return /* @__PURE__ */ jsx28(Box27, { flexDirection: "column", children: toasts.map((t) => /* @__PURE__ */ jsx28(Box27, { children: t.type === "loading" ? /* @__PURE__ */ jsxs28(
|
|
7119
|
+
return /* @__PURE__ */ jsx28(Box27, { flexDirection: "column", children: toasts.map((t) => /* @__PURE__ */ jsx28(Box27, { children: t.type === "loading" ? /* @__PURE__ */ jsxs28(Fragment4, { children: [
|
|
6813
7120
|
/* @__PURE__ */ jsx28(Spinner3, { label: "" }),
|
|
6814
7121
|
/* @__PURE__ */ jsxs28(Text26, { color: "cyan", children: [
|
|
6815
7122
|
" ",
|
|
@@ -6844,8 +7151,8 @@ var init_toast_container = __esm({
|
|
|
6844
7151
|
import { execFile as execFile2, spawn as spawn4 } from "child_process";
|
|
6845
7152
|
import { Spinner as Spinner4 } from "@inkjs/ui";
|
|
6846
7153
|
import { Box as Box28, Text as Text27, useApp, useStdout } from "ink";
|
|
6847
|
-
import { useCallback as
|
|
6848
|
-
import { Fragment as
|
|
7154
|
+
import { useCallback as useCallback16, useEffect as useEffect13, useMemo as useMemo5, useRef as useRef18, useState as useState21 } from "react";
|
|
7155
|
+
import { Fragment as Fragment5, jsx as jsx29, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
6849
7156
|
function resolvePhaseConfig(rc, config2, issueTitle, phase) {
|
|
6850
7157
|
const phasePrompts = rc.workflow?.phasePrompts ?? config2.board.workflow?.phasePrompts ?? {};
|
|
6851
7158
|
const template = phasePrompts[phase] ?? DEFAULT_PHASE_PROMPTS[phase];
|
|
@@ -6999,8 +7306,8 @@ function findSelectedIssueWithRepo(repos, selectedId) {
|
|
|
6999
7306
|
return null;
|
|
7000
7307
|
}
|
|
7001
7308
|
function RefreshAge({ lastRefresh }) {
|
|
7002
|
-
const [, setTick] =
|
|
7003
|
-
|
|
7309
|
+
const [, setTick] = useState21(0);
|
|
7310
|
+
useEffect13(() => {
|
|
7004
7311
|
const id = setInterval(() => setTick((t) => t + 1), 3e4);
|
|
7005
7312
|
return () => clearInterval(id);
|
|
7006
7313
|
}, []);
|
|
@@ -7059,15 +7366,20 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7059
7366
|
const workflowState = useWorkflowState(config2);
|
|
7060
7367
|
const { toasts, toast, handleErrorAction } = useToast();
|
|
7061
7368
|
const agentSessions = useAgentSessions(config2, workflowState, toast);
|
|
7062
|
-
const [activePanelId, setActivePanelId] =
|
|
7063
|
-
const focusPanel =
|
|
7369
|
+
const [activePanelId, setActivePanelId] = useState21(3);
|
|
7370
|
+
const focusPanel = useCallback16((id) => setActivePanelId(id), []);
|
|
7064
7371
|
const panelFocus = useMemo5(() => ({ activePanelId, focusPanel }), [activePanelId, focusPanel]);
|
|
7065
|
-
const [searchQuery, setSearchQuery] =
|
|
7066
|
-
const [mineOnly, setMineOnly] =
|
|
7067
|
-
const handleToggleMine =
|
|
7372
|
+
const [searchQuery, setSearchQuery] = useState21("");
|
|
7373
|
+
const [mineOnly, setMineOnly] = useState21(false);
|
|
7374
|
+
const handleToggleMine = useCallback16(() => {
|
|
7068
7375
|
setMineOnly((prev) => !prev);
|
|
7069
7376
|
}, []);
|
|
7070
|
-
const [
|
|
7377
|
+
const [leftPanelHidden, setLeftPanelHidden] = useState21(false);
|
|
7378
|
+
const handleToggleLeftPanel = useCallback16(() => {
|
|
7379
|
+
setLeftPanelHidden((v) => !v);
|
|
7380
|
+
setActivePanelId((id) => id === 1 || id === 2 ? 3 : id);
|
|
7381
|
+
}, []);
|
|
7382
|
+
const [logVisible, setLogVisible] = useState21(false);
|
|
7071
7383
|
const { entries: logEntries, pushEntry, undoLast, hasUndoable } = useActionLog(toast, refresh);
|
|
7072
7384
|
useAutoStatus({
|
|
7073
7385
|
config: config2,
|
|
@@ -7077,7 +7389,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7077
7389
|
pushEntry,
|
|
7078
7390
|
registerPendingMutation
|
|
7079
7391
|
});
|
|
7080
|
-
const handleEnrichmentChange =
|
|
7392
|
+
const handleEnrichmentChange = useCallback16(
|
|
7081
7393
|
(data2) => {
|
|
7082
7394
|
workflowState.updateEnrichment(data2);
|
|
7083
7395
|
},
|
|
@@ -7089,7 +7401,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7089
7401
|
enrichment: workflowState.enrichment,
|
|
7090
7402
|
onEnrichmentChange: handleEnrichmentChange
|
|
7091
7403
|
});
|
|
7092
|
-
|
|
7404
|
+
useEffect13(() => {
|
|
7093
7405
|
const last = logEntries[logEntries.length - 1];
|
|
7094
7406
|
if (last?.status === "error") setLogVisible(true);
|
|
7095
7407
|
}, [logEntries]);
|
|
@@ -7106,38 +7418,38 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7106
7418
|
return filtered.map((rd) => ({ ...rd, issues: rd.issues.filter((i) => matchesSearch(i, searchQuery)) })).filter((rd) => rd.issues.length > 0);
|
|
7107
7419
|
}, [allRepos, searchQuery, mineOnly, config2.board.assignee]);
|
|
7108
7420
|
const boardTree = useMemo5(() => buildBoardTree(repos, allActivity), [repos, allActivity]);
|
|
7109
|
-
const [selectedRepoIdx, setSelectedRepoIdx] =
|
|
7421
|
+
const [selectedRepoIdx, setSelectedRepoIdx] = useState21(0);
|
|
7110
7422
|
const clampedRepoIdx = Math.min(selectedRepoIdx, Math.max(0, boardTree.sections.length - 1));
|
|
7111
7423
|
const reposNav = {
|
|
7112
|
-
moveUp:
|
|
7113
|
-
moveDown:
|
|
7424
|
+
moveUp: useCallback16(() => setSelectedRepoIdx((i) => Math.max(0, i - 1)), []),
|
|
7425
|
+
moveDown: useCallback16(
|
|
7114
7426
|
() => setSelectedRepoIdx((i) => Math.min(Math.max(0, boardTree.sections.length - 1), i + 1)),
|
|
7115
7427
|
[boardTree.sections.length]
|
|
7116
7428
|
)
|
|
7117
7429
|
};
|
|
7118
|
-
const [selectedStatusIdx, setSelectedStatusIdx] =
|
|
7430
|
+
const [selectedStatusIdx, setSelectedStatusIdx] = useState21(0);
|
|
7119
7431
|
const selectedSection = boardTree.sections[clampedRepoIdx] ?? null;
|
|
7120
7432
|
const clampedStatusIdx = Math.min(
|
|
7121
7433
|
selectedStatusIdx,
|
|
7122
7434
|
Math.max(0, (selectedSection?.groups.length ?? 1) - 1)
|
|
7123
7435
|
);
|
|
7124
7436
|
const statusesNav = {
|
|
7125
|
-
moveUp:
|
|
7126
|
-
moveDown:
|
|
7437
|
+
moveUp: useCallback16(() => setSelectedStatusIdx((i) => Math.max(0, i - 1)), []),
|
|
7438
|
+
moveDown: useCallback16(
|
|
7127
7439
|
() => setSelectedStatusIdx(
|
|
7128
7440
|
(i) => Math.min(Math.max(0, (selectedSection?.groups.length ?? 1) - 1), i + 1)
|
|
7129
7441
|
),
|
|
7130
7442
|
[selectedSection?.groups.length]
|
|
7131
7443
|
)
|
|
7132
7444
|
};
|
|
7133
|
-
const [activitySelectedIdx, setActivitySelectedIdx] =
|
|
7445
|
+
const [activitySelectedIdx, setActivitySelectedIdx] = useState21(0);
|
|
7134
7446
|
const clampedActivityIdx = Math.min(
|
|
7135
7447
|
activitySelectedIdx,
|
|
7136
7448
|
Math.max(0, boardTree.activity.length - 1)
|
|
7137
7449
|
);
|
|
7138
7450
|
const activityNav = {
|
|
7139
|
-
moveUp:
|
|
7140
|
-
moveDown:
|
|
7451
|
+
moveUp: useCallback16(() => setActivitySelectedIdx((i) => Math.max(0, i - 1)), []),
|
|
7452
|
+
moveDown: useCallback16(
|
|
7141
7453
|
() => setActivitySelectedIdx((i) => Math.min(Math.max(0, boardTree.activity.length - 1), i + 1)),
|
|
7142
7454
|
[boardTree.activity.length]
|
|
7143
7455
|
)
|
|
@@ -7145,14 +7457,14 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7145
7457
|
const selectedRepoName = selectedSection?.sectionId ?? null;
|
|
7146
7458
|
const selectedStatusGroup = selectedSection?.groups[clampedStatusIdx] ?? null;
|
|
7147
7459
|
const selectedStatusGroupId = selectedStatusGroup?.subId ?? null;
|
|
7148
|
-
const onRepoEnter =
|
|
7460
|
+
const onRepoEnter = useCallback16(() => {
|
|
7149
7461
|
setSelectedStatusIdx(0);
|
|
7150
7462
|
panelFocus.focusPanel(3);
|
|
7151
7463
|
}, [panelFocus]);
|
|
7152
|
-
const onStatusEnter =
|
|
7464
|
+
const onStatusEnter = useCallback16(() => {
|
|
7153
7465
|
panelFocus.focusPanel(3);
|
|
7154
7466
|
}, [panelFocus]);
|
|
7155
|
-
const onActivityEnter =
|
|
7467
|
+
const onActivityEnter = useCallback16(() => {
|
|
7156
7468
|
const event = boardTree.activity[clampedActivityIdx];
|
|
7157
7469
|
if (!event) return;
|
|
7158
7470
|
const repoIdx = boardTree.sections.findIndex(
|
|
@@ -7169,7 +7481,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7169
7481
|
[boardTree.sections, selectedRepoName, selectedStatusGroupId]
|
|
7170
7482
|
);
|
|
7171
7483
|
const nav = useNavigation(navItems);
|
|
7172
|
-
const getRepoForId =
|
|
7484
|
+
const getRepoForId = useCallback16((id) => {
|
|
7173
7485
|
if (id.startsWith("gh:")) {
|
|
7174
7486
|
const parts = id.split(":");
|
|
7175
7487
|
return parts.length >= 3 ? `${parts[1]}` : null;
|
|
@@ -7177,7 +7489,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7177
7489
|
return null;
|
|
7178
7490
|
}, []);
|
|
7179
7491
|
const multiSelect = useMultiSelect(getRepoForId);
|
|
7180
|
-
|
|
7492
|
+
useEffect13(() => {
|
|
7181
7493
|
if (multiSelect.count === 0) return;
|
|
7182
7494
|
const validIds = new Set(navItems.map((i) => i.id));
|
|
7183
7495
|
multiSelect.prune(validIds);
|
|
@@ -7194,11 +7506,11 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7194
7506
|
registerPendingMutation,
|
|
7195
7507
|
clearPendingMutation
|
|
7196
7508
|
});
|
|
7197
|
-
const pendingPickRef =
|
|
7198
|
-
const labelCacheRef =
|
|
7199
|
-
const commentCacheRef =
|
|
7200
|
-
const [commentTick, setCommentTick] =
|
|
7201
|
-
const handleFetchComments =
|
|
7509
|
+
const pendingPickRef = useRef18(null);
|
|
7510
|
+
const labelCacheRef = useRef18({});
|
|
7511
|
+
const commentCacheRef = useRef18({});
|
|
7512
|
+
const [commentTick, setCommentTick] = useState21(0);
|
|
7513
|
+
const handleFetchComments = useCallback16((repo, issueNumber) => {
|
|
7202
7514
|
const key = `${repo}:${issueNumber}`;
|
|
7203
7515
|
if (commentCacheRef.current[key] !== void 0) return;
|
|
7204
7516
|
commentCacheRef.current[key] = "loading";
|
|
@@ -7211,7 +7523,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7211
7523
|
setCommentTick((t) => t + 1);
|
|
7212
7524
|
});
|
|
7213
7525
|
}, []);
|
|
7214
|
-
const handleCreateIssueWithPrompt =
|
|
7526
|
+
const handleCreateIssueWithPrompt = useCallback16(
|
|
7215
7527
|
(repo, title, body, dueDate, labels) => {
|
|
7216
7528
|
actions.handleCreateIssue(repo, title, body, dueDate, labels).then((result) => {
|
|
7217
7529
|
if (result) {
|
|
@@ -7222,7 +7534,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7222
7534
|
},
|
|
7223
7535
|
[actions, ui]
|
|
7224
7536
|
);
|
|
7225
|
-
const handleConfirmPick =
|
|
7537
|
+
const handleConfirmPick = useCallback16(() => {
|
|
7226
7538
|
const pending = pendingPickRef.current;
|
|
7227
7539
|
pendingPickRef.current = null;
|
|
7228
7540
|
ui.exitOverlay();
|
|
@@ -7240,12 +7552,12 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7240
7552
|
})
|
|
7241
7553
|
);
|
|
7242
7554
|
}, [config2, toast, refresh, ui]);
|
|
7243
|
-
const handleCancelPick =
|
|
7555
|
+
const handleCancelPick = useCallback16(() => {
|
|
7244
7556
|
pendingPickRef.current = null;
|
|
7245
7557
|
ui.exitOverlay();
|
|
7246
7558
|
}, [ui]);
|
|
7247
|
-
const [focusLabel, setFocusLabel] =
|
|
7248
|
-
const handleEnterFocus =
|
|
7559
|
+
const [focusLabel, setFocusLabel] = useState21(null);
|
|
7560
|
+
const handleEnterFocus = useCallback16(() => {
|
|
7249
7561
|
const id = nav.selectedId;
|
|
7250
7562
|
if (!id || isHeaderId(id)) return;
|
|
7251
7563
|
let label = "";
|
|
@@ -7260,11 +7572,11 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7260
7572
|
setFocusLabel(label);
|
|
7261
7573
|
ui.enterFocus();
|
|
7262
7574
|
}, [nav.selectedId, repos, config2.repos, ui]);
|
|
7263
|
-
const handleFocusExit =
|
|
7575
|
+
const handleFocusExit = useCallback16(() => {
|
|
7264
7576
|
setFocusLabel(null);
|
|
7265
7577
|
ui.exitToNormal();
|
|
7266
7578
|
}, [ui]);
|
|
7267
|
-
const handleFocusEndAction =
|
|
7579
|
+
const handleFocusEndAction = useCallback16(
|
|
7268
7580
|
(action) => {
|
|
7269
7581
|
switch (action) {
|
|
7270
7582
|
case "restart":
|
|
@@ -7290,13 +7602,13 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7290
7602
|
},
|
|
7291
7603
|
[toast, ui]
|
|
7292
7604
|
);
|
|
7293
|
-
const [focusKey, setFocusKey] =
|
|
7605
|
+
const [focusKey, setFocusKey] = useState21(0);
|
|
7294
7606
|
const { stdout } = useStdout();
|
|
7295
|
-
const [termSize, setTermSize] =
|
|
7607
|
+
const [termSize, setTermSize] = useState21({
|
|
7296
7608
|
cols: stdout?.columns ?? 80,
|
|
7297
7609
|
rows: stdout?.rows ?? 24
|
|
7298
7610
|
});
|
|
7299
|
-
|
|
7611
|
+
useEffect13(() => {
|
|
7300
7612
|
if (!stdout) return;
|
|
7301
7613
|
const onResize = () => setTermSize({ cols: stdout.columns, rows: stdout.rows });
|
|
7302
7614
|
stdout.on("resize", onResize);
|
|
@@ -7304,13 +7616,21 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7304
7616
|
stdout.off("resize", onResize);
|
|
7305
7617
|
};
|
|
7306
7618
|
}, [stdout]);
|
|
7619
|
+
const zen = useZenMode({
|
|
7620
|
+
ui,
|
|
7621
|
+
toast,
|
|
7622
|
+
termCols: termSize.cols,
|
|
7623
|
+
repos,
|
|
7624
|
+
selectedId: nav.selectedId
|
|
7625
|
+
});
|
|
7307
7626
|
const layoutMode = getLayoutMode(termSize.cols);
|
|
7308
7627
|
const detailPanelWidth = layoutMode === "wide" ? getDetailWidth(termSize.cols) : Math.floor(termSize.cols * 0.35);
|
|
7309
7628
|
const showDetailPanel = layoutMode === "wide";
|
|
7310
7629
|
const usableWidth = termSize.cols - 2;
|
|
7630
|
+
const effectiveLeftWidth = leftPanelHidden ? 0 : LEFT_COL_WIDTH;
|
|
7311
7631
|
const issuesPanelWidth = Math.max(
|
|
7312
7632
|
20,
|
|
7313
|
-
layoutMode === "wide" ? usableWidth -
|
|
7633
|
+
layoutMode === "wide" ? usableWidth - effectiveLeftWidth - getDetailWidth(termSize.cols) : layoutMode === "medium" ? usableWidth - effectiveLeftWidth : usableWidth
|
|
7314
7634
|
);
|
|
7315
7635
|
const activityPanelWidth = usableWidth;
|
|
7316
7636
|
const overlayBarRows = ui.state.mode === "search" || ui.state.mode === "overlay:comment" ? 1 : 0;
|
|
@@ -7339,9 +7659,9 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7339
7659
|
return { ...row, phaseIndicator, statusAgeDays };
|
|
7340
7660
|
});
|
|
7341
7661
|
}, [boardTree.sections, selectedRepoName, selectedStatusGroupId, workflowState, config2.repos]);
|
|
7342
|
-
const scrollRef =
|
|
7343
|
-
const prevRepoRef =
|
|
7344
|
-
const prevStatusRef =
|
|
7662
|
+
const scrollRef = useRef18(0);
|
|
7663
|
+
const prevRepoRef = useRef18(null);
|
|
7664
|
+
const prevStatusRef = useRef18(null);
|
|
7345
7665
|
if (selectedRepoName !== prevRepoRef.current || selectedStatusGroupId !== prevStatusRef.current) {
|
|
7346
7666
|
prevRepoRef.current = selectedRepoName;
|
|
7347
7667
|
prevStatusRef.current = selectedStatusGroupId;
|
|
@@ -7386,7 +7706,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7386
7706
|
return config2.repos.find((r) => r.name === selectedItem.repoName) ?? null;
|
|
7387
7707
|
}, [selectedItem.repoName, config2.repos]);
|
|
7388
7708
|
const selectedIssueWorkflow = useMemo5(() => {
|
|
7389
|
-
if (!selectedItem.issue
|
|
7709
|
+
if (!(selectedItem.issue && selectedItem.repoName)) return null;
|
|
7390
7710
|
return workflowState.getIssueWorkflow(
|
|
7391
7711
|
selectedItem.repoName,
|
|
7392
7712
|
selectedItem.issue.number,
|
|
@@ -7399,16 +7719,16 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7399
7719
|
const rd = repos.find((r) => r.repo.name === repoName);
|
|
7400
7720
|
return rd?.statusOptions ?? [];
|
|
7401
7721
|
}, [selectedItem.repoName, repos, multiSelect.count, multiSelect.constrainedRepo]);
|
|
7402
|
-
const handleOpen =
|
|
7722
|
+
const handleOpen = useCallback16(() => {
|
|
7403
7723
|
const found = findSelectedIssueWithRepo(repos, nav.selectedId);
|
|
7404
7724
|
if (found) openInBrowser(found.issue.url);
|
|
7405
7725
|
}, [repos, nav.selectedId]);
|
|
7406
|
-
const handleSlack =
|
|
7726
|
+
const handleSlack = useCallback16(() => {
|
|
7407
7727
|
const found = findSelectedIssueWithRepo(repos, nav.selectedId);
|
|
7408
7728
|
if (!found?.issue.slackThreadUrl) return;
|
|
7409
7729
|
openInBrowser(found.issue.slackThreadUrl);
|
|
7410
7730
|
}, [repos, nav.selectedId]);
|
|
7411
|
-
const handleCopyLink =
|
|
7731
|
+
const handleCopyLink = useCallback16(() => {
|
|
7412
7732
|
const found = findSelectedIssueWithRepo(repos, nav.selectedId);
|
|
7413
7733
|
if (!found) return;
|
|
7414
7734
|
const rc = config2.repos.find((r) => r.name === found.repoName);
|
|
@@ -7433,7 +7753,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7433
7753
|
toast.info(`${label} \u2014 ${found.issue.url}`);
|
|
7434
7754
|
}
|
|
7435
7755
|
}, [repos, nav.selectedId, config2.repos, toast]);
|
|
7436
|
-
const handleLaunchClaude =
|
|
7756
|
+
const handleLaunchClaude = useCallback16(() => {
|
|
7437
7757
|
const found = findSelectedIssueWithRepo(repos, nav.selectedId);
|
|
7438
7758
|
if (!found) return;
|
|
7439
7759
|
const rc = config2.repos.find((r) => r.name === found.repoName);
|
|
@@ -7459,13 +7779,14 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7459
7779
|
return;
|
|
7460
7780
|
}
|
|
7461
7781
|
toast.info(`Claude Code session opened in ${rc.shortName ?? found.repoName}`);
|
|
7462
|
-
|
|
7463
|
-
|
|
7782
|
+
zen.swapToAgent(found.issue.number);
|
|
7783
|
+
}, [repos, nav.selectedId, config2.repos, config2.board, toast, zen]);
|
|
7784
|
+
const handleEnterWorkflow = useCallback16(() => {
|
|
7464
7785
|
const found = findSelectedIssueWithRepo(repos, nav.selectedId);
|
|
7465
7786
|
if (!found) return;
|
|
7466
7787
|
ui.enterWorkflow();
|
|
7467
7788
|
}, [repos, nav.selectedId, ui]);
|
|
7468
|
-
const handleWorkflowAction =
|
|
7789
|
+
const handleWorkflowAction = useCallback16(
|
|
7469
7790
|
(action) => {
|
|
7470
7791
|
const found = findSelectedIssueWithRepo(repos, nav.selectedId);
|
|
7471
7792
|
if (!found) return;
|
|
@@ -7589,7 +7910,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7589
7910
|
},
|
|
7590
7911
|
[repos, nav.selectedId, config2, ui, toast, workflowState, agentSessions]
|
|
7591
7912
|
);
|
|
7592
|
-
const handleNudgeAction =
|
|
7913
|
+
const handleNudgeAction = useCallback16(
|
|
7593
7914
|
(action) => {
|
|
7594
7915
|
if (action.type === "snooze") {
|
|
7595
7916
|
nudges.snooze(action.repo, action.issueNumber, action.days);
|
|
@@ -7600,7 +7921,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7600
7921
|
},
|
|
7601
7922
|
[nudges, toast]
|
|
7602
7923
|
);
|
|
7603
|
-
const handleTriageAction =
|
|
7924
|
+
const handleTriageAction = useCallback16(
|
|
7604
7925
|
(action) => {
|
|
7605
7926
|
if (action.type === "snooze") {
|
|
7606
7927
|
nudges.snooze(action.repo, action.issueNumber, action.days);
|
|
@@ -7665,7 +7986,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7665
7986
|
},
|
|
7666
7987
|
[config2, agentSessions, workflowState, nudges, toast, ui]
|
|
7667
7988
|
);
|
|
7668
|
-
const handleEnterTriage =
|
|
7989
|
+
const handleEnterTriage = useCallback16(() => {
|
|
7669
7990
|
if (nudges.candidates.length === 0) {
|
|
7670
7991
|
toast.info("No stale issues to triage");
|
|
7671
7992
|
return;
|
|
@@ -7673,7 +7994,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7673
7994
|
ui.enterTriage();
|
|
7674
7995
|
}, [nudges.candidates.length, toast, ui]);
|
|
7675
7996
|
const multiSelectType = "github";
|
|
7676
|
-
const handleBulkAction =
|
|
7997
|
+
const handleBulkAction = useCallback16(
|
|
7677
7998
|
(action) => {
|
|
7678
7999
|
const ids = multiSelect.selected;
|
|
7679
8000
|
switch (action.type) {
|
|
@@ -7716,7 +8037,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7716
8037
|
},
|
|
7717
8038
|
[multiSelect, actions, ui, toast]
|
|
7718
8039
|
);
|
|
7719
|
-
const handleBulkStatusSelect =
|
|
8040
|
+
const handleBulkStatusSelect = useCallback16(
|
|
7720
8041
|
(optionId) => {
|
|
7721
8042
|
const ids = multiSelect.selected;
|
|
7722
8043
|
ui.exitOverlay();
|
|
@@ -7732,7 +8053,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7732
8053
|
},
|
|
7733
8054
|
[multiSelect, actions, ui]
|
|
7734
8055
|
);
|
|
7735
|
-
const handleFuzzySelect =
|
|
8056
|
+
const handleFuzzySelect = useCallback16(
|
|
7736
8057
|
(navId) => {
|
|
7737
8058
|
nav.select(navId);
|
|
7738
8059
|
if (navId.startsWith("gh:")) {
|
|
@@ -7753,7 +8074,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7753
8074
|
},
|
|
7754
8075
|
[nav, ui, boardTree]
|
|
7755
8076
|
);
|
|
7756
|
-
const onSearchEscape =
|
|
8077
|
+
const onSearchEscape = useCallback16(() => {
|
|
7757
8078
|
ui.exitOverlay();
|
|
7758
8079
|
setSearchQuery("");
|
|
7759
8080
|
}, [ui]);
|
|
@@ -7783,7 +8104,9 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7783
8104
|
handleToggleLog: () => setLogVisible((v) => !v),
|
|
7784
8105
|
handleLaunchClaude,
|
|
7785
8106
|
handleEnterWorkflow,
|
|
7786
|
-
handleEnterTriage
|
|
8107
|
+
handleEnterTriage,
|
|
8108
|
+
handleToggleLeftPanel,
|
|
8109
|
+
handleToggleZen: zen.handleToggleZen
|
|
7787
8110
|
},
|
|
7788
8111
|
onSearchEscape,
|
|
7789
8112
|
panelFocus,
|
|
@@ -7793,7 +8116,8 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7793
8116
|
onRepoEnter,
|
|
7794
8117
|
onStatusEnter,
|
|
7795
8118
|
onActivityEnter,
|
|
7796
|
-
showDetailPanel
|
|
8119
|
+
showDetailPanel,
|
|
8120
|
+
leftPanelHidden
|
|
7797
8121
|
});
|
|
7798
8122
|
if (status === "loading" && !data) {
|
|
7799
8123
|
return /* @__PURE__ */ jsx29(Box28, { flexDirection: "column", padding: 1, children: /* @__PURE__ */ jsx29(Spinner4, { label: "Loading dashboard..." }) });
|
|
@@ -7909,10 +8233,10 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7909
8233
|
dateStr
|
|
7910
8234
|
] }),
|
|
7911
8235
|
/* @__PURE__ */ jsx29(Text27, { children: " " }),
|
|
7912
|
-
isRefreshing ? /* @__PURE__ */ jsxs29(
|
|
8236
|
+
isRefreshing ? /* @__PURE__ */ jsxs29(Fragment5, { children: [
|
|
7913
8237
|
/* @__PURE__ */ jsx29(Spinner4, { label: "" }),
|
|
7914
8238
|
/* @__PURE__ */ jsx29(Text27, { color: "cyan", children: " Refreshing..." })
|
|
7915
|
-
] }) : /* @__PURE__ */ jsxs29(
|
|
8239
|
+
] }) : /* @__PURE__ */ jsxs29(Fragment5, { children: [
|
|
7916
8240
|
/* @__PURE__ */ jsx29(RefreshAge, { lastRefresh }),
|
|
7917
8241
|
consecutiveFailures > 0 ? /* @__PURE__ */ jsx29(Text27, { color: "red", children: " (!)" }) : null
|
|
7918
8242
|
] }),
|
|
@@ -7991,7 +8315,18 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7991
8315
|
commentsState: currentCommentsState
|
|
7992
8316
|
}
|
|
7993
8317
|
) : null,
|
|
7994
|
-
|
|
8318
|
+
ui.state.mode === "zen" ? /* @__PURE__ */ jsx29(Box28, { flexDirection: "column", height: issuesPanelHeight + ACTIVITY_HEIGHT, children: /* @__PURE__ */ jsx29(Panel, { title: "Issues (Zen)", isActive: true, width: usableWidth, children: visibleRows.map((row) => /* @__PURE__ */ jsx29(
|
|
8319
|
+
RowRenderer,
|
|
8320
|
+
{
|
|
8321
|
+
row,
|
|
8322
|
+
selectedId: nav.selectedId,
|
|
8323
|
+
selfLogin: config2.board.assignee,
|
|
8324
|
+
panelWidth: usableWidth,
|
|
8325
|
+
stalenessConfig: config2.board.workflow?.staleness
|
|
8326
|
+
},
|
|
8327
|
+
row.key
|
|
8328
|
+
)) }) }) : null,
|
|
8329
|
+
!ui.state.helpVisible && ui.state.mode !== "overlay:status" && ui.state.mode !== "overlay:create" && ui.state.mode !== "overlay:createNl" && ui.state.mode !== "overlay:bulkAction" && ui.state.mode !== "overlay:confirmPick" && ui.state.mode !== "overlay:detail" && ui.state.mode !== "overlay:nudge" && ui.state.mode !== "overlay:triage" && ui.state.mode !== "focus" && ui.state.mode !== "zen" ? /* @__PURE__ */ jsx29(
|
|
7995
8330
|
PanelLayout,
|
|
7996
8331
|
{
|
|
7997
8332
|
cols: termSize.cols,
|
|
@@ -8000,7 +8335,8 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
8000
8335
|
statusesPanel,
|
|
8001
8336
|
issuesPanel,
|
|
8002
8337
|
detailPanel,
|
|
8003
|
-
activityPanel
|
|
8338
|
+
activityPanel,
|
|
8339
|
+
hideLeftPanel: leftPanelHidden
|
|
8004
8340
|
}
|
|
8005
8341
|
) : null,
|
|
8006
8342
|
/* @__PURE__ */ jsx29(ToastContainer, { toasts }),
|
|
@@ -8037,6 +8373,7 @@ var init_dashboard = __esm({
|
|
|
8037
8373
|
init_use_toast();
|
|
8038
8374
|
init_use_ui_state();
|
|
8039
8375
|
init_use_workflow_state();
|
|
8376
|
+
init_use_zen_mode();
|
|
8040
8377
|
init_launch_claude();
|
|
8041
8378
|
init_action_log();
|
|
8042
8379
|
init_activity_panel();
|
|
@@ -8108,7 +8445,7 @@ __export(fetch_exports, {
|
|
|
8108
8445
|
fetchDashboard: () => fetchDashboard,
|
|
8109
8446
|
fetchRecentActivity: () => fetchRecentActivity
|
|
8110
8447
|
});
|
|
8111
|
-
import { execFileSync as
|
|
8448
|
+
import { execFileSync as execFileSync4 } from "child_process";
|
|
8112
8449
|
function extractSlackUrl(body) {
|
|
8113
8450
|
if (!body) return void 0;
|
|
8114
8451
|
const match = body.match(SLACK_URL_RE2);
|
|
@@ -8127,7 +8464,7 @@ function extractLinkedIssueNumbers(title, body) {
|
|
|
8127
8464
|
}
|
|
8128
8465
|
function fetchRecentActivity(repoName, shortName2) {
|
|
8129
8466
|
try {
|
|
8130
|
-
const output =
|
|
8467
|
+
const output = execFileSync4(
|
|
8131
8468
|
"gh",
|
|
8132
8469
|
[
|
|
8133
8470
|
"api",
|
|
@@ -8469,7 +8806,7 @@ var init_format_static = __esm({
|
|
|
8469
8806
|
// src/cli.ts
|
|
8470
8807
|
init_ai();
|
|
8471
8808
|
init_config();
|
|
8472
|
-
import { execFile as execFile3, execFileSync as
|
|
8809
|
+
import { execFile as execFile3, execFileSync as execFileSync5 } from "child_process";
|
|
8473
8810
|
import { promisify as promisify2 } from "util";
|
|
8474
8811
|
import { Command } from "commander";
|
|
8475
8812
|
|
|
@@ -9081,7 +9418,7 @@ async function resolveRef(ref, config2) {
|
|
|
9081
9418
|
}
|
|
9082
9419
|
}
|
|
9083
9420
|
var program = new Command();
|
|
9084
|
-
program.name("hog").description("Personal command deck \u2014 GitHub Projects dashboard with workflow orchestration").version("1.
|
|
9421
|
+
program.name("hog").description("Personal command deck \u2014 GitHub Projects dashboard with workflow orchestration").version("1.22.1").option("--json", "Force JSON output").option("--human", "Force human-readable output").hook("preAction", (thisCommand) => {
|
|
9085
9422
|
const opts = thisCommand.opts();
|
|
9086
9423
|
if (opts.json) setFormat("json");
|
|
9087
9424
|
if (opts.human) setFormat("human");
|
|
@@ -9473,7 +9810,7 @@ issueCommand.command("create <text>").description("Create a GitHub issue from na
|
|
|
9473
9810
|
const issueNumber = Number.parseInt(url.split("/").pop() ?? "0", 10);
|
|
9474
9811
|
jsonOut({ ok: true, data: { url, issueNumber, repo } });
|
|
9475
9812
|
} else {
|
|
9476
|
-
|
|
9813
|
+
execFileSync5("gh", ghArgs, { stdio: "inherit" });
|
|
9477
9814
|
}
|
|
9478
9815
|
} catch (err) {
|
|
9479
9816
|
errorOut(`gh issue create failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -9696,7 +10033,7 @@ issueCommand.command("edit <issueRef>").description("Edit issue fields (title, b
|
|
|
9696
10033
|
await execFileAsync2("gh", ghArgs, { encoding: "utf-8", timeout: 3e4 });
|
|
9697
10034
|
jsonOut({ ok: true, data: { issue: ref.issueNumber, changes } });
|
|
9698
10035
|
} else {
|
|
9699
|
-
|
|
10036
|
+
execFileSync5("gh", ghArgs, { stdio: "inherit" });
|
|
9700
10037
|
console.log(`Updated ${ref.repo.shortName}#${ref.issueNumber}: ${changes.join("; ")}`);
|
|
9701
10038
|
}
|
|
9702
10039
|
});
|