@ondrej-svec/hog 1.21.0 → 1.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +507 -178
- package/dist/cli.js.map +1 -1
- package/dist/fetch-worker.js +2 -2
- package/dist/fetch-worker.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -606,7 +606,7 @@ __export(github_exports, {
|
|
|
606
606
|
import { execFile, execFileSync as execFileSync2 } from "child_process";
|
|
607
607
|
import { promisify } from "util";
|
|
608
608
|
function runGh(args) {
|
|
609
|
-
return execFileSync2("gh", args, { encoding: "utf-8", timeout: 3e4 }).trim();
|
|
609
|
+
return execFileSync2("gh", args, { encoding: "utf-8", timeout: 3e4, stdio: "pipe" }).trim();
|
|
610
610
|
}
|
|
611
611
|
function runGhJson(args) {
|
|
612
612
|
const output = runGh(args);
|
|
@@ -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,255 @@ 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
|
+
"printf",
|
|
4098
|
+
"Issue: %s\\n\\nURL: %s\\n\\nNo Claude Code session active.\\nPress C to launch one.\\n",
|
|
4099
|
+
info.title,
|
|
4100
|
+
info.url
|
|
4101
|
+
],
|
|
4102
|
+
{
|
|
4103
|
+
encoding: "utf-8",
|
|
4104
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
4105
|
+
}
|
|
4106
|
+
);
|
|
4107
|
+
return paneId.trim() || null;
|
|
4108
|
+
} catch {
|
|
4109
|
+
return null;
|
|
4110
|
+
}
|
|
4111
|
+
}
|
|
4112
|
+
function killPane(paneId) {
|
|
4113
|
+
try {
|
|
4114
|
+
execFileSync3("tmux", ["kill-pane", "-t", paneId], {
|
|
4115
|
+
stdio: "ignore"
|
|
4116
|
+
});
|
|
4117
|
+
} catch {
|
|
4118
|
+
}
|
|
4119
|
+
}
|
|
4120
|
+
var init_tmux_pane = __esm({
|
|
4121
|
+
"src/board/tmux-pane.ts"() {
|
|
4122
|
+
"use strict";
|
|
4123
|
+
}
|
|
4124
|
+
});
|
|
4125
|
+
|
|
4126
|
+
// src/board/hooks/use-zen-mode.ts
|
|
4127
|
+
import { useCallback as useCallback13, useEffect as useEffect5, useRef as useRef11, useState as useState7 } from "react";
|
|
4128
|
+
function findIssue(repos, selectedId) {
|
|
4129
|
+
if (!selectedId?.startsWith("gh:")) return null;
|
|
4130
|
+
for (const rd of repos) {
|
|
4131
|
+
for (const issue of rd.issues) {
|
|
4132
|
+
if (`gh:${rd.repo.name}:${issue.number}` === selectedId)
|
|
4133
|
+
return { issue, repoName: rd.repo.name };
|
|
4134
|
+
}
|
|
4135
|
+
}
|
|
4136
|
+
return null;
|
|
4137
|
+
}
|
|
4138
|
+
function cleanupPane(paneId, isAgent) {
|
|
4139
|
+
if (isAgent) {
|
|
4140
|
+
breakPane(paneId);
|
|
4141
|
+
} else {
|
|
4142
|
+
killPane(paneId);
|
|
4143
|
+
}
|
|
4144
|
+
}
|
|
4145
|
+
function openOrSplitPane(issue) {
|
|
4146
|
+
const winName = agentWindowName(issue.number);
|
|
4147
|
+
const hasAgent = windowExists(winName);
|
|
4148
|
+
if (hasAgent) {
|
|
4149
|
+
const paneId2 = joinAgentPane(winName, ZEN_PANE_WIDTH_PERCENT);
|
|
4150
|
+
return paneId2 ? { paneId: paneId2, isAgent: true } : null;
|
|
4151
|
+
}
|
|
4152
|
+
const paneId = splitWithInfo({ title: issue.title, url: issue.url }, ZEN_PANE_WIDTH_PERCENT);
|
|
4153
|
+
return paneId ? { paneId, isAgent: false } : null;
|
|
4154
|
+
}
|
|
4155
|
+
function useZenMode({
|
|
4156
|
+
ui,
|
|
4157
|
+
toast,
|
|
4158
|
+
termCols,
|
|
4159
|
+
repos,
|
|
4160
|
+
selectedId
|
|
4161
|
+
}) {
|
|
4162
|
+
const [zenPaneId, setZenPaneId] = useState7(null);
|
|
4163
|
+
const [zenIsAgentPane, setZenIsAgentPane] = useState7(false);
|
|
4164
|
+
const paneRef = useRef11({
|
|
4165
|
+
id: null,
|
|
4166
|
+
isAgent: false
|
|
4167
|
+
});
|
|
4168
|
+
paneRef.current = { id: zenPaneId, isAgent: zenIsAgentPane };
|
|
4169
|
+
const exitZen = useCallback13(() => {
|
|
4170
|
+
const { id, isAgent } = paneRef.current;
|
|
4171
|
+
if (id) {
|
|
4172
|
+
cleanupPane(id, isAgent);
|
|
4173
|
+
setZenPaneId(null);
|
|
4174
|
+
setZenIsAgentPane(false);
|
|
4175
|
+
}
|
|
4176
|
+
ui.exitZen();
|
|
4177
|
+
}, [ui]);
|
|
4178
|
+
const handleToggleZen = useCallback13(() => {
|
|
4179
|
+
if (ui.state.mode === "zen") {
|
|
4180
|
+
exitZen();
|
|
4181
|
+
return;
|
|
4182
|
+
}
|
|
4183
|
+
if (!process.env["TMUX"]) {
|
|
4184
|
+
toast.error("Zen mode requires tmux");
|
|
4185
|
+
return;
|
|
4186
|
+
}
|
|
4187
|
+
if (termCols < ZEN_MIN_COLS) {
|
|
4188
|
+
toast.error("Terminal too narrow for Zen mode");
|
|
4189
|
+
return;
|
|
4190
|
+
}
|
|
4191
|
+
const found = findIssue(repos, selectedId);
|
|
4192
|
+
const result = found ? openOrSplitPane(found.issue) : null;
|
|
4193
|
+
if (!result) {
|
|
4194
|
+
toast.error("Failed to create tmux pane");
|
|
4195
|
+
return;
|
|
4196
|
+
}
|
|
4197
|
+
setZenPaneId(result.paneId);
|
|
4198
|
+
setZenIsAgentPane(result.isAgent);
|
|
4199
|
+
ui.enterZen();
|
|
4200
|
+
}, [ui, toast, termCols, exitZen, repos, selectedId]);
|
|
4201
|
+
const swapToAgent = useCallback13(
|
|
4202
|
+
(issueNumber) => {
|
|
4203
|
+
const { id, isAgent } = paneRef.current;
|
|
4204
|
+
if (ui.state.mode !== "zen" || !id) return;
|
|
4205
|
+
cleanupPane(id, isAgent);
|
|
4206
|
+
setTimeout(() => {
|
|
4207
|
+
const winName = agentWindowName(issueNumber);
|
|
4208
|
+
if (windowExists(winName)) {
|
|
4209
|
+
const newPaneId = joinAgentPane(winName, ZEN_PANE_WIDTH_PERCENT);
|
|
4210
|
+
setZenPaneId(newPaneId);
|
|
4211
|
+
setZenIsAgentPane(true);
|
|
4212
|
+
}
|
|
4213
|
+
}, 500);
|
|
4214
|
+
},
|
|
4215
|
+
[ui.state.mode]
|
|
4216
|
+
);
|
|
4217
|
+
const prevSelectedRef = useRef11(null);
|
|
4218
|
+
useEffect5(() => {
|
|
4219
|
+
if (ui.state.mode !== "zen" || !zenPaneId) {
|
|
4220
|
+
prevSelectedRef.current = selectedId;
|
|
4221
|
+
return;
|
|
4222
|
+
}
|
|
4223
|
+
if (selectedId === prevSelectedRef.current) return;
|
|
4224
|
+
prevSelectedRef.current = selectedId;
|
|
4225
|
+
const timer = setTimeout(() => {
|
|
4226
|
+
const { id, isAgent } = paneRef.current;
|
|
4227
|
+
if (!id) return;
|
|
4228
|
+
const found = findIssue(repos, selectedId);
|
|
4229
|
+
if (!found) return;
|
|
4230
|
+
cleanupPane(id, isAgent);
|
|
4231
|
+
const result = openOrSplitPane(found.issue);
|
|
4232
|
+
if (!result) {
|
|
4233
|
+
setZenPaneId(null);
|
|
4234
|
+
setZenIsAgentPane(false);
|
|
4235
|
+
ui.exitZen();
|
|
4236
|
+
toast.error("Zen pane lost \u2014 exiting zen mode");
|
|
4237
|
+
return;
|
|
4238
|
+
}
|
|
4239
|
+
setZenPaneId(result.paneId);
|
|
4240
|
+
setZenIsAgentPane(result.isAgent);
|
|
4241
|
+
}, CURSOR_FOLLOW_DEBOUNCE_MS);
|
|
4242
|
+
return () => clearTimeout(timer);
|
|
4243
|
+
}, [ui.state.mode, zenPaneId, selectedId, repos, ui, toast]);
|
|
4244
|
+
useEffect5(() => {
|
|
4245
|
+
if (ui.state.mode !== "zen" || !zenPaneId) return;
|
|
4246
|
+
const interval = setInterval(() => {
|
|
4247
|
+
if (!isPaneAlive(zenPaneId)) {
|
|
4248
|
+
exitZen();
|
|
4249
|
+
toast.info("Zen pane closed");
|
|
4250
|
+
}
|
|
4251
|
+
}, DEAD_PANE_CHECK_MS);
|
|
4252
|
+
return () => clearInterval(interval);
|
|
4253
|
+
}, [ui.state.mode, zenPaneId, exitZen, toast]);
|
|
4254
|
+
return { zenPaneId, zenIsAgentPane, handleToggleZen, swapToAgent };
|
|
4255
|
+
}
|
|
4256
|
+
var ZEN_PANE_WIDTH_PERCENT, ZEN_MIN_COLS, CURSOR_FOLLOW_DEBOUNCE_MS, DEAD_PANE_CHECK_MS;
|
|
4257
|
+
var init_use_zen_mode = __esm({
|
|
4258
|
+
"src/board/hooks/use-zen-mode.ts"() {
|
|
4259
|
+
"use strict";
|
|
4260
|
+
init_tmux_pane();
|
|
4261
|
+
ZEN_PANE_WIDTH_PERCENT = 65;
|
|
4262
|
+
ZEN_MIN_COLS = 100;
|
|
4263
|
+
CURSOR_FOLLOW_DEBOUNCE_MS = 150;
|
|
4264
|
+
DEAD_PANE_CHECK_MS = 2e3;
|
|
4265
|
+
}
|
|
4266
|
+
});
|
|
4267
|
+
|
|
3974
4268
|
// src/board/components/action-log.tsx
|
|
3975
4269
|
import { Box, Text } from "ink";
|
|
3976
|
-
import { useEffect as
|
|
4270
|
+
import { useEffect as useEffect6, useState as useState8 } from "react";
|
|
3977
4271
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3978
4272
|
function relativeTime(ago) {
|
|
3979
4273
|
const seconds = Math.floor((Date.now() - ago) / 1e3);
|
|
@@ -3994,8 +4288,8 @@ function statusColor(status) {
|
|
|
3994
4288
|
return "yellow";
|
|
3995
4289
|
}
|
|
3996
4290
|
function ActionLog({ entries }) {
|
|
3997
|
-
const [, setTick] =
|
|
3998
|
-
|
|
4291
|
+
const [, setTick] = useState8(0);
|
|
4292
|
+
useEffect6(() => {
|
|
3999
4293
|
const id = setInterval(() => setTick((t) => t + 1), 5e3);
|
|
4000
4294
|
return () => clearInterval(id);
|
|
4001
4295
|
}, []);
|
|
@@ -4045,7 +4339,7 @@ function Panel({ title, isActive, width, height, flexGrow, children }) {
|
|
|
4045
4339
|
const color = isActive ? "cyan" : "gray";
|
|
4046
4340
|
const topLine = buildTopLine(title, width);
|
|
4047
4341
|
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width, height, flexGrow, overflow: "hidden", children: [
|
|
4048
|
-
/* @__PURE__ */ jsx2(Text2, { color, children: topLine }),
|
|
4342
|
+
/* @__PURE__ */ jsx2(Box2, { flexShrink: 0, children: /* @__PURE__ */ jsx2(Text2, { color, children: topLine }) }),
|
|
4049
4343
|
/* @__PURE__ */ jsx2(
|
|
4050
4344
|
Box2,
|
|
4051
4345
|
{
|
|
@@ -4159,7 +4453,7 @@ var init_agent_activity_panel = __esm({
|
|
|
4159
4453
|
|
|
4160
4454
|
// src/board/components/detail-panel.tsx
|
|
4161
4455
|
import { Box as Box5, Text as Text5 } from "ink";
|
|
4162
|
-
import { useEffect as
|
|
4456
|
+
import { useEffect as useEffect7 } from "react";
|
|
4163
4457
|
import { Fragment, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
4164
4458
|
function stripMarkdown(text) {
|
|
4165
4459
|
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 +4505,7 @@ function DetailPanel({
|
|
|
4211
4505
|
fetchComments,
|
|
4212
4506
|
issueRepo
|
|
4213
4507
|
}) {
|
|
4214
|
-
|
|
4508
|
+
useEffect7(() => {
|
|
4215
4509
|
if (!(issue && fetchComments && issueRepo)) return;
|
|
4216
4510
|
if (commentsState !== null && commentsState !== void 0) return;
|
|
4217
4511
|
fetchComments(issueRepo, issue.number);
|
|
@@ -4310,6 +4604,12 @@ function HintBar({
|
|
|
4310
4604
|
/* @__PURE__ */ jsx6(Text6, { color: "gray", children: " Space:toggle Enter:actions Esc:cancel" })
|
|
4311
4605
|
] });
|
|
4312
4606
|
}
|
|
4607
|
+
if (uiMode === "zen") {
|
|
4608
|
+
return /* @__PURE__ */ jsxs6(Box6, { children: [
|
|
4609
|
+
/* @__PURE__ */ jsx6(Text6, { color: "green", bold: true, children: "[ZEN]" }),
|
|
4610
|
+
/* @__PURE__ */ jsx6(Text6, { color: "gray", children: " j/k:nav C:claude Z/Esc:exit q:quit" })
|
|
4611
|
+
] });
|
|
4612
|
+
}
|
|
4313
4613
|
if (uiMode === "focus") {
|
|
4314
4614
|
return /* @__PURE__ */ jsx6(Box6, { children: /* @__PURE__ */ jsx6(Text6, { color: "magenta", bold: true, children: "[FOCUS] Focus mode \u2014 Esc to exit" }) });
|
|
4315
4615
|
}
|
|
@@ -4340,7 +4640,7 @@ function HintBar({
|
|
|
4340
4640
|
0: "j/k:scroll Esc:close ? help",
|
|
4341
4641
|
1: "j/k:move Enter:filter 0-4:panel ? help",
|
|
4342
4642
|
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`,
|
|
4643
|
+
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
4644
|
4: "j/k:scroll Enter:jump r:refresh 0-4:panel ? help"
|
|
4345
4645
|
};
|
|
4346
4646
|
return /* @__PURE__ */ jsxs6(Box6, { children: [
|
|
@@ -4361,7 +4661,7 @@ var init_hint_bar = __esm({
|
|
|
4361
4661
|
|
|
4362
4662
|
// src/board/components/bulk-action-menu.tsx
|
|
4363
4663
|
import { Box as Box7, Text as Text7, useInput as useInput2 } from "ink";
|
|
4364
|
-
import { useState as
|
|
4664
|
+
import { useState as useState9 } from "react";
|
|
4365
4665
|
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
4366
4666
|
function getMenuItems(selectionType) {
|
|
4367
4667
|
if (selectionType === "github") {
|
|
@@ -4375,7 +4675,7 @@ function getMenuItems(selectionType) {
|
|
|
4375
4675
|
}
|
|
4376
4676
|
function BulkActionMenu({ count, selectionType, onSelect, onCancel }) {
|
|
4377
4677
|
const items = getMenuItems(selectionType);
|
|
4378
|
-
const [selectedIdx, setSelectedIdx] =
|
|
4678
|
+
const [selectedIdx, setSelectedIdx] = useState9(0);
|
|
4379
4679
|
useInput2((input2, key) => {
|
|
4380
4680
|
if (key.escape) return onCancel();
|
|
4381
4681
|
if (key.return) {
|
|
@@ -4478,7 +4778,7 @@ import { tmpdir } from "os";
|
|
|
4478
4778
|
import { join as join5 } from "path";
|
|
4479
4779
|
import { TextInput } from "@inkjs/ui";
|
|
4480
4780
|
import { Box as Box8, Text as Text8, useInput as useInput3, useStdin } from "ink";
|
|
4481
|
-
import { useEffect as
|
|
4781
|
+
import { useEffect as useEffect8, useRef as useRef12, useState as useState10 } from "react";
|
|
4482
4782
|
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
4483
4783
|
function CommentInput({
|
|
4484
4784
|
issueNumber,
|
|
@@ -4487,13 +4787,13 @@ function CommentInput({
|
|
|
4487
4787
|
onPauseRefresh,
|
|
4488
4788
|
onResumeRefresh
|
|
4489
4789
|
}) {
|
|
4490
|
-
const [value, setValue] =
|
|
4491
|
-
const [editing, setEditing] =
|
|
4790
|
+
const [value, setValue] = useState10("");
|
|
4791
|
+
const [editing, setEditing] = useState10(false);
|
|
4492
4792
|
const { setRawMode } = useStdin();
|
|
4493
|
-
const onSubmitRef =
|
|
4494
|
-
const onCancelRef =
|
|
4495
|
-
const onPauseRef =
|
|
4496
|
-
const onResumeRef =
|
|
4793
|
+
const onSubmitRef = useRef12(onSubmit);
|
|
4794
|
+
const onCancelRef = useRef12(onCancel);
|
|
4795
|
+
const onPauseRef = useRef12(onPauseRefresh);
|
|
4796
|
+
const onResumeRef = useRef12(onResumeRefresh);
|
|
4497
4797
|
onSubmitRef.current = onSubmit;
|
|
4498
4798
|
onCancelRef.current = onCancel;
|
|
4499
4799
|
onPauseRef.current = onPauseRefresh;
|
|
@@ -4508,7 +4808,7 @@ function CommentInput({
|
|
|
4508
4808
|
setEditing(true);
|
|
4509
4809
|
}
|
|
4510
4810
|
});
|
|
4511
|
-
|
|
4811
|
+
useEffect8(() => {
|
|
4512
4812
|
if (!editing) return;
|
|
4513
4813
|
const editor = resolveEditor();
|
|
4514
4814
|
if (!editor) {
|
|
@@ -4601,7 +4901,7 @@ var init_confirm_prompt = __esm({
|
|
|
4601
4901
|
// src/board/components/label-picker.tsx
|
|
4602
4902
|
import { Spinner } from "@inkjs/ui";
|
|
4603
4903
|
import { Box as Box10, Text as Text10, useInput as useInput5 } from "ink";
|
|
4604
|
-
import { useEffect as
|
|
4904
|
+
import { useEffect as useEffect9, useRef as useRef13, useState as useState11 } from "react";
|
|
4605
4905
|
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
4606
4906
|
function LabelPicker({
|
|
4607
4907
|
repo,
|
|
@@ -4611,13 +4911,13 @@ function LabelPicker({
|
|
|
4611
4911
|
onCancel,
|
|
4612
4912
|
onError
|
|
4613
4913
|
}) {
|
|
4614
|
-
const [labels, setLabels] =
|
|
4615
|
-
const [loading, setLoading] =
|
|
4616
|
-
const [fetchAttempted, setFetchAttempted] =
|
|
4617
|
-
const [selected, setSelected] =
|
|
4618
|
-
const [cursor, setCursor] =
|
|
4619
|
-
const submittedRef =
|
|
4620
|
-
|
|
4914
|
+
const [labels, setLabels] = useState11(labelCache[repo] ?? null);
|
|
4915
|
+
const [loading, setLoading] = useState11(labels === null);
|
|
4916
|
+
const [fetchAttempted, setFetchAttempted] = useState11(false);
|
|
4917
|
+
const [selected, setSelected] = useState11(new Set(currentLabels));
|
|
4918
|
+
const [cursor, setCursor] = useState11(0);
|
|
4919
|
+
const submittedRef = useRef13(false);
|
|
4920
|
+
useEffect9(() => {
|
|
4621
4921
|
if (labels !== null || fetchAttempted) return;
|
|
4622
4922
|
setFetchAttempted(true);
|
|
4623
4923
|
setLoading(true);
|
|
@@ -4720,7 +5020,7 @@ var init_label_picker = __esm({
|
|
|
4720
5020
|
// src/board/components/create-issue-form.tsx
|
|
4721
5021
|
import { TextInput as TextInput2 } from "@inkjs/ui";
|
|
4722
5022
|
import { Box as Box11, Text as Text11, useInput as useInput6 } from "ink";
|
|
4723
|
-
import { useState as
|
|
5023
|
+
import { useState as useState12 } from "react";
|
|
4724
5024
|
import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
4725
5025
|
function CreateIssueForm({
|
|
4726
5026
|
repos,
|
|
@@ -4733,9 +5033,9 @@ function CreateIssueForm({
|
|
|
4733
5033
|
0,
|
|
4734
5034
|
repos.findIndex((r) => r.name === defaultRepo)
|
|
4735
5035
|
) : 0;
|
|
4736
|
-
const [repoIdx, setRepoIdx] =
|
|
4737
|
-
const [title, setTitle] =
|
|
4738
|
-
const [field, setField] =
|
|
5036
|
+
const [repoIdx, setRepoIdx] = useState12(defaultRepoIdx);
|
|
5037
|
+
const [title, setTitle] = useState12("");
|
|
5038
|
+
const [field, setField] = useState12("title");
|
|
4739
5039
|
useInput6((input2, key) => {
|
|
4740
5040
|
if (field === "labels") return;
|
|
4741
5041
|
if (key.escape) return onCancel();
|
|
@@ -4837,7 +5137,7 @@ import { mkdtempSync as mkdtempSync2, readFileSync as readFileSync7, rmSync as r
|
|
|
4837
5137
|
import { tmpdir as tmpdir2 } from "os";
|
|
4838
5138
|
import { join as join6 } from "path";
|
|
4839
5139
|
import { Box as Box12, Text as Text12, useStdin as useStdin2 } from "ink";
|
|
4840
|
-
import { useEffect as
|
|
5140
|
+
import { useEffect as useEffect10, useRef as useRef14, useState as useState13 } from "react";
|
|
4841
5141
|
import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
4842
5142
|
function buildEditorFile(issue, repoName, statusOptions, repoLabels) {
|
|
4843
5143
|
const statusNames = statusOptions.map((o) => o.name).join(", ");
|
|
@@ -4921,15 +5221,15 @@ function EditIssueOverlay({
|
|
|
4921
5221
|
onToastError,
|
|
4922
5222
|
onPushEntry
|
|
4923
5223
|
}) {
|
|
4924
|
-
const [editing, setEditing] =
|
|
5224
|
+
const [editing, setEditing] = useState13(true);
|
|
4925
5225
|
const { setRawMode } = useStdin2();
|
|
4926
|
-
const onDoneRef =
|
|
4927
|
-
const onPauseRef =
|
|
4928
|
-
const onResumeRef =
|
|
5226
|
+
const onDoneRef = useRef14(onDone);
|
|
5227
|
+
const onPauseRef = useRef14(onPauseRefresh);
|
|
5228
|
+
const onResumeRef = useRef14(onResumeRefresh);
|
|
4929
5229
|
onDoneRef.current = onDone;
|
|
4930
5230
|
onPauseRef.current = onPauseRefresh;
|
|
4931
5231
|
onResumeRef.current = onResumeRefresh;
|
|
4932
|
-
|
|
5232
|
+
useEffect10(() => {
|
|
4933
5233
|
if (!editing) return;
|
|
4934
5234
|
const editor = resolveEditor();
|
|
4935
5235
|
if (!editor) {
|
|
@@ -5097,7 +5397,7 @@ var init_edit_issue_overlay = __esm({
|
|
|
5097
5397
|
|
|
5098
5398
|
// src/board/components/focus-mode.tsx
|
|
5099
5399
|
import { Box as Box13, Text as Text13, useInput as useInput7 } from "ink";
|
|
5100
|
-
import { useCallback as
|
|
5400
|
+
import { useCallback as useCallback14, useEffect as useEffect11, useRef as useRef15, useState as useState14 } from "react";
|
|
5101
5401
|
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
5102
5402
|
function formatTime(secs) {
|
|
5103
5403
|
const m = Math.floor(secs / 60);
|
|
@@ -5105,10 +5405,10 @@ function formatTime(secs) {
|
|
|
5105
5405
|
return `${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
|
|
5106
5406
|
}
|
|
5107
5407
|
function FocusMode({ label, durationSec, onExit, onEndAction }) {
|
|
5108
|
-
const [remaining, setRemaining] =
|
|
5109
|
-
const [timerDone, setTimerDone] =
|
|
5110
|
-
const bellSentRef =
|
|
5111
|
-
|
|
5408
|
+
const [remaining, setRemaining] = useState14(durationSec);
|
|
5409
|
+
const [timerDone, setTimerDone] = useState14(false);
|
|
5410
|
+
const bellSentRef = useRef15(false);
|
|
5411
|
+
useEffect11(() => {
|
|
5112
5412
|
if (timerDone) return;
|
|
5113
5413
|
const interval = setInterval(() => {
|
|
5114
5414
|
setRemaining((prev) => {
|
|
@@ -5122,13 +5422,13 @@ function FocusMode({ label, durationSec, onExit, onEndAction }) {
|
|
|
5122
5422
|
}, 1e3);
|
|
5123
5423
|
return () => clearInterval(interval);
|
|
5124
5424
|
}, [timerDone]);
|
|
5125
|
-
|
|
5425
|
+
useEffect11(() => {
|
|
5126
5426
|
if (timerDone && !bellSentRef.current) {
|
|
5127
5427
|
bellSentRef.current = true;
|
|
5128
5428
|
process.stdout.write("\x07");
|
|
5129
5429
|
}
|
|
5130
5430
|
}, [timerDone]);
|
|
5131
|
-
const handleInput =
|
|
5431
|
+
const handleInput = useCallback14(
|
|
5132
5432
|
(input2, key) => {
|
|
5133
5433
|
if (key.escape) {
|
|
5134
5434
|
if (timerDone) {
|
|
@@ -5206,7 +5506,7 @@ var init_focus_mode = __esm({
|
|
|
5206
5506
|
import { TextInput as TextInput3 } from "@inkjs/ui";
|
|
5207
5507
|
import { Fzf } from "fzf";
|
|
5208
5508
|
import { Box as Box14, Text as Text14, useInput as useInput8 } from "ink";
|
|
5209
|
-
import { useMemo as useMemo4, useState as
|
|
5509
|
+
import { useMemo as useMemo4, useState as useState15 } from "react";
|
|
5210
5510
|
import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
5211
5511
|
function keepCursorVisible(cursor, offset, visible) {
|
|
5212
5512
|
if (cursor < offset) return cursor;
|
|
@@ -5214,9 +5514,9 @@ function keepCursorVisible(cursor, offset, visible) {
|
|
|
5214
5514
|
return offset;
|
|
5215
5515
|
}
|
|
5216
5516
|
function FuzzyPicker({ repos, onSelect, onClose }) {
|
|
5217
|
-
const [query, setQuery] =
|
|
5218
|
-
const [cursor, setCursor] =
|
|
5219
|
-
const [scrollOffset, setScrollOffset] =
|
|
5517
|
+
const [query, setQuery] = useState15("");
|
|
5518
|
+
const [cursor, setCursor] = useState15(0);
|
|
5519
|
+
const [scrollOffset, setScrollOffset] = useState15(0);
|
|
5220
5520
|
const allIssues = useMemo4(() => {
|
|
5221
5521
|
const items = [];
|
|
5222
5522
|
for (const rd of repos) {
|
|
@@ -5437,6 +5737,8 @@ var init_help_overlay = __esm({
|
|
|
5437
5737
|
{ key: "F", desc: "Fuzzy find issue (telescope-style)" },
|
|
5438
5738
|
{ key: "t", desc: "Toggle @me filter (my issues only)" },
|
|
5439
5739
|
{ key: "f", desc: "Focus mode" },
|
|
5740
|
+
{ key: "Z", desc: "Zen mode (tmux split with Claude Code)" },
|
|
5741
|
+
{ key: "H", desc: "Toggle left panel (repos/statuses)" },
|
|
5440
5742
|
{ key: "?", desc: "Toggle help" },
|
|
5441
5743
|
{ key: "Esc", desc: "Close overlay / Back to normal" }
|
|
5442
5744
|
]
|
|
@@ -5480,7 +5782,7 @@ import { tmpdir as tmpdir3 } from "os";
|
|
|
5480
5782
|
import { join as join7 } from "path";
|
|
5481
5783
|
import { Spinner as Spinner2, TextInput as TextInput4 } from "@inkjs/ui";
|
|
5482
5784
|
import { Box as Box16, Text as Text16, useInput as useInput10, useStdin as useStdin3 } from "ink";
|
|
5483
|
-
import { useCallback as
|
|
5785
|
+
import { useCallback as useCallback15, useEffect as useEffect12, useRef as useRef16, useState as useState16 } from "react";
|
|
5484
5786
|
import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
5485
5787
|
function NlCreateOverlay({
|
|
5486
5788
|
repos,
|
|
@@ -5492,19 +5794,19 @@ function NlCreateOverlay({
|
|
|
5492
5794
|
onResumeRefresh,
|
|
5493
5795
|
onLlmFallback
|
|
5494
5796
|
}) {
|
|
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 =
|
|
5797
|
+
const [, setInput] = useState16("");
|
|
5798
|
+
const [isParsing, setIsParsing] = useState16(false);
|
|
5799
|
+
const [parsed, setParsed] = useState16(null);
|
|
5800
|
+
const [parseError, setParseError] = useState16(null);
|
|
5801
|
+
const [step, setStep] = useState16("input");
|
|
5802
|
+
const [body, setBody] = useState16("");
|
|
5803
|
+
const [editingBody, setEditingBody] = useState16(false);
|
|
5804
|
+
const submittedRef = useRef16(false);
|
|
5805
|
+
const parseParamsRef = useRef16(null);
|
|
5806
|
+
const onSubmitRef = useRef16(onSubmit);
|
|
5807
|
+
const onCancelRef = useRef16(onCancel);
|
|
5808
|
+
const onPauseRef = useRef16(onPauseRefresh);
|
|
5809
|
+
const onResumeRef = useRef16(onResumeRefresh);
|
|
5508
5810
|
onSubmitRef.current = onSubmit;
|
|
5509
5811
|
onCancelRef.current = onCancel;
|
|
5510
5812
|
onPauseRef.current = onPauseRefresh;
|
|
@@ -5514,7 +5816,7 @@ function NlCreateOverlay({
|
|
|
5514
5816
|
0,
|
|
5515
5817
|
repos.findIndex((r) => r.name === defaultRepoName)
|
|
5516
5818
|
) : 0;
|
|
5517
|
-
const [repoIdx, setRepoIdx] =
|
|
5819
|
+
const [repoIdx, setRepoIdx] = useState16(defaultRepoIdx);
|
|
5518
5820
|
const selectedRepo = repos[repoIdx];
|
|
5519
5821
|
useInput10((inputChar, key) => {
|
|
5520
5822
|
if (isParsing || editingBody) return;
|
|
@@ -5541,7 +5843,7 @@ function NlCreateOverlay({
|
|
|
5541
5843
|
setEditingBody(true);
|
|
5542
5844
|
}
|
|
5543
5845
|
});
|
|
5544
|
-
|
|
5846
|
+
useEffect12(() => {
|
|
5545
5847
|
if (!editingBody) return;
|
|
5546
5848
|
const editor = resolveEditor();
|
|
5547
5849
|
if (!editor) {
|
|
@@ -5573,7 +5875,7 @@ function NlCreateOverlay({
|
|
|
5573
5875
|
setEditingBody(false);
|
|
5574
5876
|
}
|
|
5575
5877
|
}, [editingBody, body, setRawMode]);
|
|
5576
|
-
const handleInputSubmit =
|
|
5878
|
+
const handleInputSubmit = useCallback15(
|
|
5577
5879
|
(text) => {
|
|
5578
5880
|
const trimmed = text.trim();
|
|
5579
5881
|
if (!trimmed) return;
|
|
@@ -5585,7 +5887,7 @@ function NlCreateOverlay({
|
|
|
5585
5887
|
},
|
|
5586
5888
|
[selectedRepo, labelCache]
|
|
5587
5889
|
);
|
|
5588
|
-
|
|
5890
|
+
useEffect12(() => {
|
|
5589
5891
|
if (!(isParsing && parseParamsRef.current)) return;
|
|
5590
5892
|
const { input: capturedInput, validLabels } = parseParamsRef.current;
|
|
5591
5893
|
extractIssueFields(capturedInput, {
|
|
@@ -5717,10 +6019,10 @@ var init_nl_create_overlay = __esm({
|
|
|
5717
6019
|
|
|
5718
6020
|
// src/board/components/nudge-overlay.tsx
|
|
5719
6021
|
import { Box as Box17, Text as Text17, useInput as useInput11 } from "ink";
|
|
5720
|
-
import { useState as
|
|
6022
|
+
import { useState as useState17 } from "react";
|
|
5721
6023
|
import { jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
5722
6024
|
function NudgeOverlay({ candidates, onAction, onCancel }) {
|
|
5723
|
-
const [selectedIdx, setSelectedIdx] =
|
|
6025
|
+
const [selectedIdx, setSelectedIdx] = useState17(0);
|
|
5724
6026
|
useInput11((input2, key) => {
|
|
5725
6027
|
if (key.escape) {
|
|
5726
6028
|
onAction({ type: "dismiss" });
|
|
@@ -5841,7 +6143,7 @@ var init_search_bar = __esm({
|
|
|
5841
6143
|
|
|
5842
6144
|
// src/board/components/status-picker.tsx
|
|
5843
6145
|
import { Box as Box19, Text as Text19, useInput as useInput12 } from "ink";
|
|
5844
|
-
import { useRef as
|
|
6146
|
+
import { useRef as useRef17, useState as useState18 } from "react";
|
|
5845
6147
|
import { jsx as jsx19, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
5846
6148
|
function isTerminal(name) {
|
|
5847
6149
|
return TERMINAL_STATUS_RE.test(name);
|
|
@@ -5889,12 +6191,12 @@ function StatusPicker({
|
|
|
5889
6191
|
onCancel,
|
|
5890
6192
|
showTerminalStatuses = true
|
|
5891
6193
|
}) {
|
|
5892
|
-
const [selectedIdx, setSelectedIdx] =
|
|
6194
|
+
const [selectedIdx, setSelectedIdx] = useState18(() => {
|
|
5893
6195
|
const idx = options.findIndex((o) => o.name === currentStatus);
|
|
5894
6196
|
return idx >= 0 ? idx : 0;
|
|
5895
6197
|
});
|
|
5896
|
-
const [confirmingTerminal, setConfirmingTerminal] =
|
|
5897
|
-
const submittedRef =
|
|
6198
|
+
const [confirmingTerminal, setConfirmingTerminal] = useState18(false);
|
|
6199
|
+
const submittedRef = useRef17(false);
|
|
5898
6200
|
useInput12((input2, key) => {
|
|
5899
6201
|
if (confirmingTerminal) {
|
|
5900
6202
|
handleConfirmInput(input2, key, {
|
|
@@ -5962,12 +6264,12 @@ var init_status_picker = __esm({
|
|
|
5962
6264
|
|
|
5963
6265
|
// src/board/components/triage-overlay.tsx
|
|
5964
6266
|
import { Box as Box20, Text as Text20, useInput as useInput13 } from "ink";
|
|
5965
|
-
import { useState as
|
|
6267
|
+
import { useState as useState19 } from "react";
|
|
5966
6268
|
import { jsx as jsx20, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
5967
6269
|
function TriageOverlay({ candidates, phases, onAction, onCancel }) {
|
|
5968
|
-
const [selected, setSelected] =
|
|
5969
|
-
const [cursorIdx, setCursorIdx] =
|
|
5970
|
-
const [phaseIdx, setPhaseIdx] =
|
|
6270
|
+
const [selected, setSelected] = useState19(() => /* @__PURE__ */ new Set());
|
|
6271
|
+
const [cursorIdx, setCursorIdx] = useState19(0);
|
|
6272
|
+
const [phaseIdx, setPhaseIdx] = useState19(0);
|
|
5971
6273
|
useInput13((input2, key) => {
|
|
5972
6274
|
if (key.escape) {
|
|
5973
6275
|
onCancel();
|
|
@@ -6105,7 +6407,7 @@ var init_triage_overlay = __esm({
|
|
|
6105
6407
|
|
|
6106
6408
|
// src/board/components/workflow-overlay.tsx
|
|
6107
6409
|
import { Box as Box21, Text as Text21, useInput as useInput14 } from "ink";
|
|
6108
|
-
import { useState as
|
|
6410
|
+
import { useState as useState20 } from "react";
|
|
6109
6411
|
import { jsx as jsx21, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
6110
6412
|
function phaseIcon(state) {
|
|
6111
6413
|
switch (state) {
|
|
@@ -6135,7 +6437,7 @@ function WorkflowOverlay({
|
|
|
6135
6437
|
onAction,
|
|
6136
6438
|
onCancel
|
|
6137
6439
|
}) {
|
|
6138
|
-
const [selectedIdx, setSelectedIdx] =
|
|
6440
|
+
const [selectedIdx, setSelectedIdx] = useState20(0);
|
|
6139
6441
|
useInput14((input2, key) => {
|
|
6140
6442
|
if (key.escape) {
|
|
6141
6443
|
onCancel();
|
|
@@ -6413,7 +6715,7 @@ var init_overlay_renderer = __esm({
|
|
|
6413
6715
|
|
|
6414
6716
|
// src/board/components/panel-layout.tsx
|
|
6415
6717
|
import { Box as Box22 } from "ink";
|
|
6416
|
-
import { jsx as jsx23, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
6718
|
+
import { Fragment as Fragment3, jsx as jsx23, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
6417
6719
|
function getLayoutMode(cols) {
|
|
6418
6720
|
if (cols >= WIDE_THRESHOLD) return "wide";
|
|
6419
6721
|
if (cols >= MEDIUM_THRESHOLD) return "medium";
|
|
@@ -6429,17 +6731,18 @@ function PanelLayout({
|
|
|
6429
6731
|
statusesPanel,
|
|
6430
6732
|
issuesPanel,
|
|
6431
6733
|
detailPanel,
|
|
6432
|
-
activityPanel
|
|
6734
|
+
activityPanel,
|
|
6735
|
+
hideLeftPanel
|
|
6433
6736
|
}) {
|
|
6434
6737
|
const mode = getLayoutMode(cols);
|
|
6435
6738
|
if (mode === "wide") {
|
|
6436
6739
|
const detailWidth = getDetailWidth(cols);
|
|
6437
6740
|
return /* @__PURE__ */ jsxs23(Box22, { flexDirection: "column", children: [
|
|
6438
6741
|
/* @__PURE__ */ jsxs23(Box22, { height: issuesPanelHeight, children: [
|
|
6439
|
-
/* @__PURE__ */ jsxs23(Box22, { flexDirection: "column", width: LEFT_COL_WIDTH, children: [
|
|
6742
|
+
!hideLeftPanel ? /* @__PURE__ */ jsxs23(Box22, { flexDirection: "column", width: LEFT_COL_WIDTH, children: [
|
|
6440
6743
|
reposPanel,
|
|
6441
6744
|
statusesPanel
|
|
6442
|
-
] }),
|
|
6745
|
+
] }) : null,
|
|
6443
6746
|
/* @__PURE__ */ jsx23(Box22, { flexGrow: 1, flexDirection: "column", children: issuesPanel }),
|
|
6444
6747
|
/* @__PURE__ */ jsx23(Box22, { width: detailWidth, flexDirection: "column", children: detailPanel })
|
|
6445
6748
|
] }),
|
|
@@ -6449,18 +6752,20 @@ function PanelLayout({
|
|
|
6449
6752
|
if (mode === "medium") {
|
|
6450
6753
|
return /* @__PURE__ */ jsxs23(Box22, { flexDirection: "column", children: [
|
|
6451
6754
|
/* @__PURE__ */ jsxs23(Box22, { height: issuesPanelHeight, children: [
|
|
6452
|
-
/* @__PURE__ */ jsxs23(Box22, { flexDirection: "column", width: LEFT_COL_WIDTH, children: [
|
|
6755
|
+
!hideLeftPanel ? /* @__PURE__ */ jsxs23(Box22, { flexDirection: "column", width: LEFT_COL_WIDTH, children: [
|
|
6453
6756
|
reposPanel,
|
|
6454
6757
|
statusesPanel
|
|
6455
|
-
] }),
|
|
6758
|
+
] }) : null,
|
|
6456
6759
|
/* @__PURE__ */ jsx23(Box22, { flexGrow: 1, flexDirection: "column", children: issuesPanel })
|
|
6457
6760
|
] }),
|
|
6458
6761
|
/* @__PURE__ */ jsx23(Box22, { height: ACTIVITY_HEIGHT, children: activityPanel })
|
|
6459
6762
|
] });
|
|
6460
6763
|
}
|
|
6461
6764
|
return /* @__PURE__ */ jsxs23(Box22, { flexDirection: "column", children: [
|
|
6462
|
-
|
|
6463
|
-
|
|
6765
|
+
!hideLeftPanel ? /* @__PURE__ */ jsxs23(Fragment3, { children: [
|
|
6766
|
+
reposPanel,
|
|
6767
|
+
statusesPanel
|
|
6768
|
+
] }) : null,
|
|
6464
6769
|
/* @__PURE__ */ jsx23(Box22, { flexGrow: 1, flexDirection: "column", children: issuesPanel }),
|
|
6465
6770
|
/* @__PURE__ */ jsx23(Box22, { height: ACTIVITY_HEIGHT, children: activityPanel })
|
|
6466
6771
|
] });
|
|
@@ -6806,10 +7111,10 @@ var init_statuses_panel = __esm({
|
|
|
6806
7111
|
// src/board/components/toast-container.tsx
|
|
6807
7112
|
import { Spinner as Spinner3 } from "@inkjs/ui";
|
|
6808
7113
|
import { Box as Box27, Text as Text26 } from "ink";
|
|
6809
|
-
import { Fragment as
|
|
7114
|
+
import { Fragment as Fragment4, jsx as jsx28, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
6810
7115
|
function ToastContainer({ toasts }) {
|
|
6811
7116
|
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(
|
|
7117
|
+
return /* @__PURE__ */ jsx28(Box27, { flexDirection: "column", children: toasts.map((t) => /* @__PURE__ */ jsx28(Box27, { children: t.type === "loading" ? /* @__PURE__ */ jsxs28(Fragment4, { children: [
|
|
6813
7118
|
/* @__PURE__ */ jsx28(Spinner3, { label: "" }),
|
|
6814
7119
|
/* @__PURE__ */ jsxs28(Text26, { color: "cyan", children: [
|
|
6815
7120
|
" ",
|
|
@@ -6844,8 +7149,8 @@ var init_toast_container = __esm({
|
|
|
6844
7149
|
import { execFile as execFile2, spawn as spawn4 } from "child_process";
|
|
6845
7150
|
import { Spinner as Spinner4 } from "@inkjs/ui";
|
|
6846
7151
|
import { Box as Box28, Text as Text27, useApp, useStdout } from "ink";
|
|
6847
|
-
import { useCallback as
|
|
6848
|
-
import { Fragment as
|
|
7152
|
+
import { useCallback as useCallback16, useEffect as useEffect13, useMemo as useMemo5, useRef as useRef18, useState as useState21 } from "react";
|
|
7153
|
+
import { Fragment as Fragment5, jsx as jsx29, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
6849
7154
|
function resolvePhaseConfig(rc, config2, issueTitle, phase) {
|
|
6850
7155
|
const phasePrompts = rc.workflow?.phasePrompts ?? config2.board.workflow?.phasePrompts ?? {};
|
|
6851
7156
|
const template = phasePrompts[phase] ?? DEFAULT_PHASE_PROMPTS[phase];
|
|
@@ -6999,8 +7304,8 @@ function findSelectedIssueWithRepo(repos, selectedId) {
|
|
|
6999
7304
|
return null;
|
|
7000
7305
|
}
|
|
7001
7306
|
function RefreshAge({ lastRefresh }) {
|
|
7002
|
-
const [, setTick] =
|
|
7003
|
-
|
|
7307
|
+
const [, setTick] = useState21(0);
|
|
7308
|
+
useEffect13(() => {
|
|
7004
7309
|
const id = setInterval(() => setTick((t) => t + 1), 3e4);
|
|
7005
7310
|
return () => clearInterval(id);
|
|
7006
7311
|
}, []);
|
|
@@ -7059,15 +7364,20 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7059
7364
|
const workflowState = useWorkflowState(config2);
|
|
7060
7365
|
const { toasts, toast, handleErrorAction } = useToast();
|
|
7061
7366
|
const agentSessions = useAgentSessions(config2, workflowState, toast);
|
|
7062
|
-
const [activePanelId, setActivePanelId] =
|
|
7063
|
-
const focusPanel =
|
|
7367
|
+
const [activePanelId, setActivePanelId] = useState21(3);
|
|
7368
|
+
const focusPanel = useCallback16((id) => setActivePanelId(id), []);
|
|
7064
7369
|
const panelFocus = useMemo5(() => ({ activePanelId, focusPanel }), [activePanelId, focusPanel]);
|
|
7065
|
-
const [searchQuery, setSearchQuery] =
|
|
7066
|
-
const [mineOnly, setMineOnly] =
|
|
7067
|
-
const handleToggleMine =
|
|
7370
|
+
const [searchQuery, setSearchQuery] = useState21("");
|
|
7371
|
+
const [mineOnly, setMineOnly] = useState21(false);
|
|
7372
|
+
const handleToggleMine = useCallback16(() => {
|
|
7068
7373
|
setMineOnly((prev) => !prev);
|
|
7069
7374
|
}, []);
|
|
7070
|
-
const [
|
|
7375
|
+
const [leftPanelHidden, setLeftPanelHidden] = useState21(false);
|
|
7376
|
+
const handleToggleLeftPanel = useCallback16(() => {
|
|
7377
|
+
setLeftPanelHidden((v) => !v);
|
|
7378
|
+
setActivePanelId((id) => id === 1 || id === 2 ? 3 : id);
|
|
7379
|
+
}, []);
|
|
7380
|
+
const [logVisible, setLogVisible] = useState21(false);
|
|
7071
7381
|
const { entries: logEntries, pushEntry, undoLast, hasUndoable } = useActionLog(toast, refresh);
|
|
7072
7382
|
useAutoStatus({
|
|
7073
7383
|
config: config2,
|
|
@@ -7077,7 +7387,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7077
7387
|
pushEntry,
|
|
7078
7388
|
registerPendingMutation
|
|
7079
7389
|
});
|
|
7080
|
-
const handleEnrichmentChange =
|
|
7390
|
+
const handleEnrichmentChange = useCallback16(
|
|
7081
7391
|
(data2) => {
|
|
7082
7392
|
workflowState.updateEnrichment(data2);
|
|
7083
7393
|
},
|
|
@@ -7089,14 +7399,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7089
7399
|
enrichment: workflowState.enrichment,
|
|
7090
7400
|
onEnrichmentChange: handleEnrichmentChange
|
|
7091
7401
|
});
|
|
7092
|
-
|
|
7093
|
-
useEffect12(() => {
|
|
7094
|
-
if (nudges.shouldShowDailyNudge && !dailyNudgeShownRef.current && ui.canAct) {
|
|
7095
|
-
dailyNudgeShownRef.current = true;
|
|
7096
|
-
ui.enterNudge();
|
|
7097
|
-
}
|
|
7098
|
-
}, [nudges.shouldShowDailyNudge, ui]);
|
|
7099
|
-
useEffect12(() => {
|
|
7402
|
+
useEffect13(() => {
|
|
7100
7403
|
const last = logEntries[logEntries.length - 1];
|
|
7101
7404
|
if (last?.status === "error") setLogVisible(true);
|
|
7102
7405
|
}, [logEntries]);
|
|
@@ -7113,38 +7416,38 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7113
7416
|
return filtered.map((rd) => ({ ...rd, issues: rd.issues.filter((i) => matchesSearch(i, searchQuery)) })).filter((rd) => rd.issues.length > 0);
|
|
7114
7417
|
}, [allRepos, searchQuery, mineOnly, config2.board.assignee]);
|
|
7115
7418
|
const boardTree = useMemo5(() => buildBoardTree(repos, allActivity), [repos, allActivity]);
|
|
7116
|
-
const [selectedRepoIdx, setSelectedRepoIdx] =
|
|
7419
|
+
const [selectedRepoIdx, setSelectedRepoIdx] = useState21(0);
|
|
7117
7420
|
const clampedRepoIdx = Math.min(selectedRepoIdx, Math.max(0, boardTree.sections.length - 1));
|
|
7118
7421
|
const reposNav = {
|
|
7119
|
-
moveUp:
|
|
7120
|
-
moveDown:
|
|
7422
|
+
moveUp: useCallback16(() => setSelectedRepoIdx((i) => Math.max(0, i - 1)), []),
|
|
7423
|
+
moveDown: useCallback16(
|
|
7121
7424
|
() => setSelectedRepoIdx((i) => Math.min(Math.max(0, boardTree.sections.length - 1), i + 1)),
|
|
7122
7425
|
[boardTree.sections.length]
|
|
7123
7426
|
)
|
|
7124
7427
|
};
|
|
7125
|
-
const [selectedStatusIdx, setSelectedStatusIdx] =
|
|
7428
|
+
const [selectedStatusIdx, setSelectedStatusIdx] = useState21(0);
|
|
7126
7429
|
const selectedSection = boardTree.sections[clampedRepoIdx] ?? null;
|
|
7127
7430
|
const clampedStatusIdx = Math.min(
|
|
7128
7431
|
selectedStatusIdx,
|
|
7129
7432
|
Math.max(0, (selectedSection?.groups.length ?? 1) - 1)
|
|
7130
7433
|
);
|
|
7131
7434
|
const statusesNav = {
|
|
7132
|
-
moveUp:
|
|
7133
|
-
moveDown:
|
|
7435
|
+
moveUp: useCallback16(() => setSelectedStatusIdx((i) => Math.max(0, i - 1)), []),
|
|
7436
|
+
moveDown: useCallback16(
|
|
7134
7437
|
() => setSelectedStatusIdx(
|
|
7135
7438
|
(i) => Math.min(Math.max(0, (selectedSection?.groups.length ?? 1) - 1), i + 1)
|
|
7136
7439
|
),
|
|
7137
7440
|
[selectedSection?.groups.length]
|
|
7138
7441
|
)
|
|
7139
7442
|
};
|
|
7140
|
-
const [activitySelectedIdx, setActivitySelectedIdx] =
|
|
7443
|
+
const [activitySelectedIdx, setActivitySelectedIdx] = useState21(0);
|
|
7141
7444
|
const clampedActivityIdx = Math.min(
|
|
7142
7445
|
activitySelectedIdx,
|
|
7143
7446
|
Math.max(0, boardTree.activity.length - 1)
|
|
7144
7447
|
);
|
|
7145
7448
|
const activityNav = {
|
|
7146
|
-
moveUp:
|
|
7147
|
-
moveDown:
|
|
7449
|
+
moveUp: useCallback16(() => setActivitySelectedIdx((i) => Math.max(0, i - 1)), []),
|
|
7450
|
+
moveDown: useCallback16(
|
|
7148
7451
|
() => setActivitySelectedIdx((i) => Math.min(Math.max(0, boardTree.activity.length - 1), i + 1)),
|
|
7149
7452
|
[boardTree.activity.length]
|
|
7150
7453
|
)
|
|
@@ -7152,14 +7455,14 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7152
7455
|
const selectedRepoName = selectedSection?.sectionId ?? null;
|
|
7153
7456
|
const selectedStatusGroup = selectedSection?.groups[clampedStatusIdx] ?? null;
|
|
7154
7457
|
const selectedStatusGroupId = selectedStatusGroup?.subId ?? null;
|
|
7155
|
-
const onRepoEnter =
|
|
7458
|
+
const onRepoEnter = useCallback16(() => {
|
|
7156
7459
|
setSelectedStatusIdx(0);
|
|
7157
7460
|
panelFocus.focusPanel(3);
|
|
7158
7461
|
}, [panelFocus]);
|
|
7159
|
-
const onStatusEnter =
|
|
7462
|
+
const onStatusEnter = useCallback16(() => {
|
|
7160
7463
|
panelFocus.focusPanel(3);
|
|
7161
7464
|
}, [panelFocus]);
|
|
7162
|
-
const onActivityEnter =
|
|
7465
|
+
const onActivityEnter = useCallback16(() => {
|
|
7163
7466
|
const event = boardTree.activity[clampedActivityIdx];
|
|
7164
7467
|
if (!event) return;
|
|
7165
7468
|
const repoIdx = boardTree.sections.findIndex(
|
|
@@ -7176,7 +7479,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7176
7479
|
[boardTree.sections, selectedRepoName, selectedStatusGroupId]
|
|
7177
7480
|
);
|
|
7178
7481
|
const nav = useNavigation(navItems);
|
|
7179
|
-
const getRepoForId =
|
|
7482
|
+
const getRepoForId = useCallback16((id) => {
|
|
7180
7483
|
if (id.startsWith("gh:")) {
|
|
7181
7484
|
const parts = id.split(":");
|
|
7182
7485
|
return parts.length >= 3 ? `${parts[1]}` : null;
|
|
@@ -7184,7 +7487,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7184
7487
|
return null;
|
|
7185
7488
|
}, []);
|
|
7186
7489
|
const multiSelect = useMultiSelect(getRepoForId);
|
|
7187
|
-
|
|
7490
|
+
useEffect13(() => {
|
|
7188
7491
|
if (multiSelect.count === 0) return;
|
|
7189
7492
|
const validIds = new Set(navItems.map((i) => i.id));
|
|
7190
7493
|
multiSelect.prune(validIds);
|
|
@@ -7201,11 +7504,11 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7201
7504
|
registerPendingMutation,
|
|
7202
7505
|
clearPendingMutation
|
|
7203
7506
|
});
|
|
7204
|
-
const pendingPickRef =
|
|
7205
|
-
const labelCacheRef =
|
|
7206
|
-
const commentCacheRef =
|
|
7207
|
-
const [commentTick, setCommentTick] =
|
|
7208
|
-
const handleFetchComments =
|
|
7507
|
+
const pendingPickRef = useRef18(null);
|
|
7508
|
+
const labelCacheRef = useRef18({});
|
|
7509
|
+
const commentCacheRef = useRef18({});
|
|
7510
|
+
const [commentTick, setCommentTick] = useState21(0);
|
|
7511
|
+
const handleFetchComments = useCallback16((repo, issueNumber) => {
|
|
7209
7512
|
const key = `${repo}:${issueNumber}`;
|
|
7210
7513
|
if (commentCacheRef.current[key] !== void 0) return;
|
|
7211
7514
|
commentCacheRef.current[key] = "loading";
|
|
@@ -7218,7 +7521,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7218
7521
|
setCommentTick((t) => t + 1);
|
|
7219
7522
|
});
|
|
7220
7523
|
}, []);
|
|
7221
|
-
const handleCreateIssueWithPrompt =
|
|
7524
|
+
const handleCreateIssueWithPrompt = useCallback16(
|
|
7222
7525
|
(repo, title, body, dueDate, labels) => {
|
|
7223
7526
|
actions.handleCreateIssue(repo, title, body, dueDate, labels).then((result) => {
|
|
7224
7527
|
if (result) {
|
|
@@ -7229,7 +7532,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7229
7532
|
},
|
|
7230
7533
|
[actions, ui]
|
|
7231
7534
|
);
|
|
7232
|
-
const handleConfirmPick =
|
|
7535
|
+
const handleConfirmPick = useCallback16(() => {
|
|
7233
7536
|
const pending = pendingPickRef.current;
|
|
7234
7537
|
pendingPickRef.current = null;
|
|
7235
7538
|
ui.exitOverlay();
|
|
@@ -7247,12 +7550,12 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7247
7550
|
})
|
|
7248
7551
|
);
|
|
7249
7552
|
}, [config2, toast, refresh, ui]);
|
|
7250
|
-
const handleCancelPick =
|
|
7553
|
+
const handleCancelPick = useCallback16(() => {
|
|
7251
7554
|
pendingPickRef.current = null;
|
|
7252
7555
|
ui.exitOverlay();
|
|
7253
7556
|
}, [ui]);
|
|
7254
|
-
const [focusLabel, setFocusLabel] =
|
|
7255
|
-
const handleEnterFocus =
|
|
7557
|
+
const [focusLabel, setFocusLabel] = useState21(null);
|
|
7558
|
+
const handleEnterFocus = useCallback16(() => {
|
|
7256
7559
|
const id = nav.selectedId;
|
|
7257
7560
|
if (!id || isHeaderId(id)) return;
|
|
7258
7561
|
let label = "";
|
|
@@ -7267,11 +7570,11 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7267
7570
|
setFocusLabel(label);
|
|
7268
7571
|
ui.enterFocus();
|
|
7269
7572
|
}, [nav.selectedId, repos, config2.repos, ui]);
|
|
7270
|
-
const handleFocusExit =
|
|
7573
|
+
const handleFocusExit = useCallback16(() => {
|
|
7271
7574
|
setFocusLabel(null);
|
|
7272
7575
|
ui.exitToNormal();
|
|
7273
7576
|
}, [ui]);
|
|
7274
|
-
const handleFocusEndAction =
|
|
7577
|
+
const handleFocusEndAction = useCallback16(
|
|
7275
7578
|
(action) => {
|
|
7276
7579
|
switch (action) {
|
|
7277
7580
|
case "restart":
|
|
@@ -7297,13 +7600,13 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7297
7600
|
},
|
|
7298
7601
|
[toast, ui]
|
|
7299
7602
|
);
|
|
7300
|
-
const [focusKey, setFocusKey] =
|
|
7603
|
+
const [focusKey, setFocusKey] = useState21(0);
|
|
7301
7604
|
const { stdout } = useStdout();
|
|
7302
|
-
const [termSize, setTermSize] =
|
|
7605
|
+
const [termSize, setTermSize] = useState21({
|
|
7303
7606
|
cols: stdout?.columns ?? 80,
|
|
7304
7607
|
rows: stdout?.rows ?? 24
|
|
7305
7608
|
});
|
|
7306
|
-
|
|
7609
|
+
useEffect13(() => {
|
|
7307
7610
|
if (!stdout) return;
|
|
7308
7611
|
const onResize = () => setTermSize({ cols: stdout.columns, rows: stdout.rows });
|
|
7309
7612
|
stdout.on("resize", onResize);
|
|
@@ -7311,13 +7614,21 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7311
7614
|
stdout.off("resize", onResize);
|
|
7312
7615
|
};
|
|
7313
7616
|
}, [stdout]);
|
|
7617
|
+
const zen = useZenMode({
|
|
7618
|
+
ui,
|
|
7619
|
+
toast,
|
|
7620
|
+
termCols: termSize.cols,
|
|
7621
|
+
repos,
|
|
7622
|
+
selectedId: nav.selectedId
|
|
7623
|
+
});
|
|
7314
7624
|
const layoutMode = getLayoutMode(termSize.cols);
|
|
7315
7625
|
const detailPanelWidth = layoutMode === "wide" ? getDetailWidth(termSize.cols) : Math.floor(termSize.cols * 0.35);
|
|
7316
7626
|
const showDetailPanel = layoutMode === "wide";
|
|
7317
7627
|
const usableWidth = termSize.cols - 2;
|
|
7628
|
+
const effectiveLeftWidth = leftPanelHidden ? 0 : LEFT_COL_WIDTH;
|
|
7318
7629
|
const issuesPanelWidth = Math.max(
|
|
7319
7630
|
20,
|
|
7320
|
-
layoutMode === "wide" ? usableWidth -
|
|
7631
|
+
layoutMode === "wide" ? usableWidth - effectiveLeftWidth - getDetailWidth(termSize.cols) : layoutMode === "medium" ? usableWidth - effectiveLeftWidth : usableWidth
|
|
7321
7632
|
);
|
|
7322
7633
|
const activityPanelWidth = usableWidth;
|
|
7323
7634
|
const overlayBarRows = ui.state.mode === "search" || ui.state.mode === "overlay:comment" ? 1 : 0;
|
|
@@ -7328,6 +7639,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7328
7639
|
termSize.rows - CHROME_ROWS - overlayBarRows - toastRows - logPaneRows
|
|
7329
7640
|
);
|
|
7330
7641
|
const issuesPanelHeight = Math.max(5, totalPanelHeight - ACTIVITY_HEIGHT);
|
|
7642
|
+
const contentRowCount = Math.max(1, issuesPanelHeight - 2);
|
|
7331
7643
|
const flatRows = useMemo5(() => {
|
|
7332
7644
|
const rows = buildFlatRowsForRepo(boardTree.sections, selectedRepoName, selectedStatusGroupId);
|
|
7333
7645
|
return rows.map((row) => {
|
|
@@ -7345,9 +7657,9 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7345
7657
|
return { ...row, phaseIndicator, statusAgeDays };
|
|
7346
7658
|
});
|
|
7347
7659
|
}, [boardTree.sections, selectedRepoName, selectedStatusGroupId, workflowState, config2.repos]);
|
|
7348
|
-
const scrollRef =
|
|
7349
|
-
const prevRepoRef =
|
|
7350
|
-
const prevStatusRef =
|
|
7660
|
+
const scrollRef = useRef18(0);
|
|
7661
|
+
const prevRepoRef = useRef18(null);
|
|
7662
|
+
const prevStatusRef = useRef18(null);
|
|
7351
7663
|
if (selectedRepoName !== prevRepoRef.current || selectedStatusGroupId !== prevStatusRef.current) {
|
|
7352
7664
|
prevRepoRef.current = selectedRepoName;
|
|
7353
7665
|
prevStatusRef.current = selectedStatusGroupId;
|
|
@@ -7360,17 +7672,17 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7360
7672
|
if (selectedRowIdx >= 0) {
|
|
7361
7673
|
if (selectedRowIdx < scrollRef.current) {
|
|
7362
7674
|
scrollRef.current = selectedRowIdx;
|
|
7363
|
-
} else if (selectedRowIdx >= scrollRef.current +
|
|
7364
|
-
scrollRef.current = selectedRowIdx -
|
|
7675
|
+
} else if (selectedRowIdx >= scrollRef.current + contentRowCount) {
|
|
7676
|
+
scrollRef.current = selectedRowIdx - contentRowCount + 1;
|
|
7365
7677
|
}
|
|
7366
7678
|
}
|
|
7367
|
-
const maxOffset = Math.max(0, flatRows.length -
|
|
7679
|
+
const maxOffset = Math.max(0, flatRows.length - contentRowCount);
|
|
7368
7680
|
scrollRef.current = Math.max(0, Math.min(scrollRef.current, maxOffset));
|
|
7369
|
-
const visibleRows = flatRows.slice(scrollRef.current, scrollRef.current +
|
|
7681
|
+
const visibleRows = flatRows.slice(scrollRef.current, scrollRef.current + contentRowCount);
|
|
7370
7682
|
const hasMoreAbove = scrollRef.current > 0;
|
|
7371
|
-
const hasMoreBelow = scrollRef.current +
|
|
7683
|
+
const hasMoreBelow = scrollRef.current + contentRowCount < flatRows.length;
|
|
7372
7684
|
const aboveCount = scrollRef.current;
|
|
7373
|
-
const belowCount = flatRows.length - scrollRef.current -
|
|
7685
|
+
const belowCount = flatRows.length - scrollRef.current - contentRowCount;
|
|
7374
7686
|
const selectedItem = useMemo5(() => {
|
|
7375
7687
|
const id = nav.selectedId;
|
|
7376
7688
|
if (!id || isHeaderId(id)) return { issue: null, repoName: null };
|
|
@@ -7392,7 +7704,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7392
7704
|
return config2.repos.find((r) => r.name === selectedItem.repoName) ?? null;
|
|
7393
7705
|
}, [selectedItem.repoName, config2.repos]);
|
|
7394
7706
|
const selectedIssueWorkflow = useMemo5(() => {
|
|
7395
|
-
if (!selectedItem.issue
|
|
7707
|
+
if (!(selectedItem.issue && selectedItem.repoName)) return null;
|
|
7396
7708
|
return workflowState.getIssueWorkflow(
|
|
7397
7709
|
selectedItem.repoName,
|
|
7398
7710
|
selectedItem.issue.number,
|
|
@@ -7405,16 +7717,16 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7405
7717
|
const rd = repos.find((r) => r.repo.name === repoName);
|
|
7406
7718
|
return rd?.statusOptions ?? [];
|
|
7407
7719
|
}, [selectedItem.repoName, repos, multiSelect.count, multiSelect.constrainedRepo]);
|
|
7408
|
-
const handleOpen =
|
|
7720
|
+
const handleOpen = useCallback16(() => {
|
|
7409
7721
|
const found = findSelectedIssueWithRepo(repos, nav.selectedId);
|
|
7410
7722
|
if (found) openInBrowser(found.issue.url);
|
|
7411
7723
|
}, [repos, nav.selectedId]);
|
|
7412
|
-
const handleSlack =
|
|
7724
|
+
const handleSlack = useCallback16(() => {
|
|
7413
7725
|
const found = findSelectedIssueWithRepo(repos, nav.selectedId);
|
|
7414
7726
|
if (!found?.issue.slackThreadUrl) return;
|
|
7415
7727
|
openInBrowser(found.issue.slackThreadUrl);
|
|
7416
7728
|
}, [repos, nav.selectedId]);
|
|
7417
|
-
const handleCopyLink =
|
|
7729
|
+
const handleCopyLink = useCallback16(() => {
|
|
7418
7730
|
const found = findSelectedIssueWithRepo(repos, nav.selectedId);
|
|
7419
7731
|
if (!found) return;
|
|
7420
7732
|
const rc = config2.repos.find((r) => r.name === found.repoName);
|
|
@@ -7439,7 +7751,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7439
7751
|
toast.info(`${label} \u2014 ${found.issue.url}`);
|
|
7440
7752
|
}
|
|
7441
7753
|
}, [repos, nav.selectedId, config2.repos, toast]);
|
|
7442
|
-
const handleLaunchClaude =
|
|
7754
|
+
const handleLaunchClaude = useCallback16(() => {
|
|
7443
7755
|
const found = findSelectedIssueWithRepo(repos, nav.selectedId);
|
|
7444
7756
|
if (!found) return;
|
|
7445
7757
|
const rc = config2.repos.find((r) => r.name === found.repoName);
|
|
@@ -7465,13 +7777,14 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7465
7777
|
return;
|
|
7466
7778
|
}
|
|
7467
7779
|
toast.info(`Claude Code session opened in ${rc.shortName ?? found.repoName}`);
|
|
7468
|
-
|
|
7469
|
-
|
|
7780
|
+
zen.swapToAgent(found.issue.number);
|
|
7781
|
+
}, [repos, nav.selectedId, config2.repos, config2.board, toast, zen]);
|
|
7782
|
+
const handleEnterWorkflow = useCallback16(() => {
|
|
7470
7783
|
const found = findSelectedIssueWithRepo(repos, nav.selectedId);
|
|
7471
7784
|
if (!found) return;
|
|
7472
7785
|
ui.enterWorkflow();
|
|
7473
7786
|
}, [repos, nav.selectedId, ui]);
|
|
7474
|
-
const handleWorkflowAction =
|
|
7787
|
+
const handleWorkflowAction = useCallback16(
|
|
7475
7788
|
(action) => {
|
|
7476
7789
|
const found = findSelectedIssueWithRepo(repos, nav.selectedId);
|
|
7477
7790
|
if (!found) return;
|
|
@@ -7595,7 +7908,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7595
7908
|
},
|
|
7596
7909
|
[repos, nav.selectedId, config2, ui, toast, workflowState, agentSessions]
|
|
7597
7910
|
);
|
|
7598
|
-
const handleNudgeAction =
|
|
7911
|
+
const handleNudgeAction = useCallback16(
|
|
7599
7912
|
(action) => {
|
|
7600
7913
|
if (action.type === "snooze") {
|
|
7601
7914
|
nudges.snooze(action.repo, action.issueNumber, action.days);
|
|
@@ -7606,7 +7919,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7606
7919
|
},
|
|
7607
7920
|
[nudges, toast]
|
|
7608
7921
|
);
|
|
7609
|
-
const handleTriageAction =
|
|
7922
|
+
const handleTriageAction = useCallback16(
|
|
7610
7923
|
(action) => {
|
|
7611
7924
|
if (action.type === "snooze") {
|
|
7612
7925
|
nudges.snooze(action.repo, action.issueNumber, action.days);
|
|
@@ -7671,7 +7984,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7671
7984
|
},
|
|
7672
7985
|
[config2, agentSessions, workflowState, nudges, toast, ui]
|
|
7673
7986
|
);
|
|
7674
|
-
const handleEnterTriage =
|
|
7987
|
+
const handleEnterTriage = useCallback16(() => {
|
|
7675
7988
|
if (nudges.candidates.length === 0) {
|
|
7676
7989
|
toast.info("No stale issues to triage");
|
|
7677
7990
|
return;
|
|
@@ -7679,7 +7992,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7679
7992
|
ui.enterTriage();
|
|
7680
7993
|
}, [nudges.candidates.length, toast, ui]);
|
|
7681
7994
|
const multiSelectType = "github";
|
|
7682
|
-
const handleBulkAction =
|
|
7995
|
+
const handleBulkAction = useCallback16(
|
|
7683
7996
|
(action) => {
|
|
7684
7997
|
const ids = multiSelect.selected;
|
|
7685
7998
|
switch (action.type) {
|
|
@@ -7722,7 +8035,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7722
8035
|
},
|
|
7723
8036
|
[multiSelect, actions, ui, toast]
|
|
7724
8037
|
);
|
|
7725
|
-
const handleBulkStatusSelect =
|
|
8038
|
+
const handleBulkStatusSelect = useCallback16(
|
|
7726
8039
|
(optionId) => {
|
|
7727
8040
|
const ids = multiSelect.selected;
|
|
7728
8041
|
ui.exitOverlay();
|
|
@@ -7738,7 +8051,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7738
8051
|
},
|
|
7739
8052
|
[multiSelect, actions, ui]
|
|
7740
8053
|
);
|
|
7741
|
-
const handleFuzzySelect =
|
|
8054
|
+
const handleFuzzySelect = useCallback16(
|
|
7742
8055
|
(navId) => {
|
|
7743
8056
|
nav.select(navId);
|
|
7744
8057
|
if (navId.startsWith("gh:")) {
|
|
@@ -7759,7 +8072,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7759
8072
|
},
|
|
7760
8073
|
[nav, ui, boardTree]
|
|
7761
8074
|
);
|
|
7762
|
-
const onSearchEscape =
|
|
8075
|
+
const onSearchEscape = useCallback16(() => {
|
|
7763
8076
|
ui.exitOverlay();
|
|
7764
8077
|
setSearchQuery("");
|
|
7765
8078
|
}, [ui]);
|
|
@@ -7789,7 +8102,9 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7789
8102
|
handleToggleLog: () => setLogVisible((v) => !v),
|
|
7790
8103
|
handleLaunchClaude,
|
|
7791
8104
|
handleEnterWorkflow,
|
|
7792
|
-
handleEnterTriage
|
|
8105
|
+
handleEnterTriage,
|
|
8106
|
+
handleToggleLeftPanel,
|
|
8107
|
+
handleToggleZen: zen.handleToggleZen
|
|
7793
8108
|
},
|
|
7794
8109
|
onSearchEscape,
|
|
7795
8110
|
panelFocus,
|
|
@@ -7799,7 +8114,8 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7799
8114
|
onRepoEnter,
|
|
7800
8115
|
onStatusEnter,
|
|
7801
8116
|
onActivityEnter,
|
|
7802
|
-
showDetailPanel
|
|
8117
|
+
showDetailPanel,
|
|
8118
|
+
leftPanelHidden
|
|
7803
8119
|
});
|
|
7804
8120
|
if (status === "loading" && !data) {
|
|
7805
8121
|
return /* @__PURE__ */ jsx29(Box28, { flexDirection: "column", padding: 1, children: /* @__PURE__ */ jsx29(Spinner4, { label: "Loading dashboard..." }) });
|
|
@@ -7915,10 +8231,10 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7915
8231
|
dateStr
|
|
7916
8232
|
] }),
|
|
7917
8233
|
/* @__PURE__ */ jsx29(Text27, { children: " " }),
|
|
7918
|
-
isRefreshing ? /* @__PURE__ */ jsxs29(
|
|
8234
|
+
isRefreshing ? /* @__PURE__ */ jsxs29(Fragment5, { children: [
|
|
7919
8235
|
/* @__PURE__ */ jsx29(Spinner4, { label: "" }),
|
|
7920
8236
|
/* @__PURE__ */ jsx29(Text27, { color: "cyan", children: " Refreshing..." })
|
|
7921
|
-
] }) : /* @__PURE__ */ jsxs29(
|
|
8237
|
+
] }) : /* @__PURE__ */ jsxs29(Fragment5, { children: [
|
|
7922
8238
|
/* @__PURE__ */ jsx29(RefreshAge, { lastRefresh }),
|
|
7923
8239
|
consecutiveFailures > 0 ? /* @__PURE__ */ jsx29(Text27, { color: "red", children: " (!)" }) : null
|
|
7924
8240
|
] }),
|
|
@@ -7997,7 +8313,18 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
7997
8313
|
commentsState: currentCommentsState
|
|
7998
8314
|
}
|
|
7999
8315
|
) : null,
|
|
8000
|
-
|
|
8316
|
+
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(
|
|
8317
|
+
RowRenderer,
|
|
8318
|
+
{
|
|
8319
|
+
row,
|
|
8320
|
+
selectedId: nav.selectedId,
|
|
8321
|
+
selfLogin: config2.board.assignee,
|
|
8322
|
+
panelWidth: usableWidth,
|
|
8323
|
+
stalenessConfig: config2.board.workflow?.staleness
|
|
8324
|
+
},
|
|
8325
|
+
row.key
|
|
8326
|
+
)) }) }) : null,
|
|
8327
|
+
!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(
|
|
8001
8328
|
PanelLayout,
|
|
8002
8329
|
{
|
|
8003
8330
|
cols: termSize.cols,
|
|
@@ -8006,7 +8333,8 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
8006
8333
|
statusesPanel,
|
|
8007
8334
|
issuesPanel,
|
|
8008
8335
|
detailPanel,
|
|
8009
|
-
activityPanel
|
|
8336
|
+
activityPanel,
|
|
8337
|
+
hideLeftPanel: leftPanelHidden
|
|
8010
8338
|
}
|
|
8011
8339
|
) : null,
|
|
8012
8340
|
/* @__PURE__ */ jsx29(ToastContainer, { toasts }),
|
|
@@ -8043,6 +8371,7 @@ var init_dashboard = __esm({
|
|
|
8043
8371
|
init_use_toast();
|
|
8044
8372
|
init_use_ui_state();
|
|
8045
8373
|
init_use_workflow_state();
|
|
8374
|
+
init_use_zen_mode();
|
|
8046
8375
|
init_launch_claude();
|
|
8047
8376
|
init_action_log();
|
|
8048
8377
|
init_activity_panel();
|
|
@@ -8114,7 +8443,7 @@ __export(fetch_exports, {
|
|
|
8114
8443
|
fetchDashboard: () => fetchDashboard,
|
|
8115
8444
|
fetchRecentActivity: () => fetchRecentActivity
|
|
8116
8445
|
});
|
|
8117
|
-
import { execFileSync as
|
|
8446
|
+
import { execFileSync as execFileSync4 } from "child_process";
|
|
8118
8447
|
function extractSlackUrl(body) {
|
|
8119
8448
|
if (!body) return void 0;
|
|
8120
8449
|
const match = body.match(SLACK_URL_RE2);
|
|
@@ -8133,7 +8462,7 @@ function extractLinkedIssueNumbers(title, body) {
|
|
|
8133
8462
|
}
|
|
8134
8463
|
function fetchRecentActivity(repoName, shortName2) {
|
|
8135
8464
|
try {
|
|
8136
|
-
const output =
|
|
8465
|
+
const output = execFileSync4(
|
|
8137
8466
|
"gh",
|
|
8138
8467
|
[
|
|
8139
8468
|
"api",
|
|
@@ -8143,7 +8472,7 @@ function fetchRecentActivity(repoName, shortName2) {
|
|
|
8143
8472
|
"-q",
|
|
8144
8473
|
'.[] | select(.type == "IssuesEvent" or .type == "IssueCommentEvent" or .type == "PullRequestEvent" or .type == "CreateEvent") | {type: .type, actor: .actor.login, action: .payload.action, number: (.payload.issue.number // .payload.pull_request.number), title: (.payload.issue.title // .payload.pull_request.title), body: (.payload.comment.body // .payload.pull_request.body), created_at: .created_at, ref: .payload.ref, ref_type: .payload.ref_type, merged: .payload.pull_request.merged}'
|
|
8145
8474
|
],
|
|
8146
|
-
{ encoding: "utf-8", timeout: 15e3 }
|
|
8475
|
+
{ encoding: "utf-8", timeout: 15e3, stdio: "pipe" }
|
|
8147
8476
|
);
|
|
8148
8477
|
const cutoff = Date.now() - 24 * 60 * 60 * 1e3;
|
|
8149
8478
|
const events = [];
|
|
@@ -8475,7 +8804,7 @@ var init_format_static = __esm({
|
|
|
8475
8804
|
// src/cli.ts
|
|
8476
8805
|
init_ai();
|
|
8477
8806
|
init_config();
|
|
8478
|
-
import { execFile as execFile3, execFileSync as
|
|
8807
|
+
import { execFile as execFile3, execFileSync as execFileSync5 } from "child_process";
|
|
8479
8808
|
import { promisify as promisify2 } from "util";
|
|
8480
8809
|
import { Command } from "commander";
|
|
8481
8810
|
|
|
@@ -9087,7 +9416,7 @@ async function resolveRef(ref, config2) {
|
|
|
9087
9416
|
}
|
|
9088
9417
|
}
|
|
9089
9418
|
var program = new Command();
|
|
9090
|
-
program.name("hog").description("Personal command deck \u2014 GitHub Projects dashboard with workflow orchestration").version("1.
|
|
9419
|
+
program.name("hog").description("Personal command deck \u2014 GitHub Projects dashboard with workflow orchestration").version("1.22.0").option("--json", "Force JSON output").option("--human", "Force human-readable output").hook("preAction", (thisCommand) => {
|
|
9091
9420
|
const opts = thisCommand.opts();
|
|
9092
9421
|
if (opts.json) setFormat("json");
|
|
9093
9422
|
if (opts.human) setFormat("human");
|
|
@@ -9479,7 +9808,7 @@ issueCommand.command("create <text>").description("Create a GitHub issue from na
|
|
|
9479
9808
|
const issueNumber = Number.parseInt(url.split("/").pop() ?? "0", 10);
|
|
9480
9809
|
jsonOut({ ok: true, data: { url, issueNumber, repo } });
|
|
9481
9810
|
} else {
|
|
9482
|
-
|
|
9811
|
+
execFileSync5("gh", ghArgs, { stdio: "inherit" });
|
|
9483
9812
|
}
|
|
9484
9813
|
} catch (err) {
|
|
9485
9814
|
errorOut(`gh issue create failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -9702,7 +10031,7 @@ issueCommand.command("edit <issueRef>").description("Edit issue fields (title, b
|
|
|
9702
10031
|
await execFileAsync2("gh", ghArgs, { encoding: "utf-8", timeout: 3e4 });
|
|
9703
10032
|
jsonOut({ ok: true, data: { issue: ref.issueNumber, changes } });
|
|
9704
10033
|
} else {
|
|
9705
|
-
|
|
10034
|
+
execFileSync5("gh", ghArgs, { stdio: "inherit" });
|
|
9706
10035
|
console.log(`Updated ${ref.repo.shortName}#${ref.issueNumber}: ${changes.join("; ")}`);
|
|
9707
10036
|
}
|
|
9708
10037
|
});
|