@ondrej-svec/hog 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +127 -28
- package/dist/cli.js +118 -24
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ Your personal command deck — a unified task dashboard for GitHub Projects and
|
|
|
9
9
|
|
|
10
10
|
```sh
|
|
11
11
|
npm install -g @ondrej-svec/hog
|
|
12
|
-
hog init
|
|
12
|
+
hog init # interactive setup wizard
|
|
13
13
|
hog board --live
|
|
14
14
|
```
|
|
15
15
|
|
|
@@ -17,18 +17,22 @@ Requires **Node.js 22+** and the [GitHub CLI](https://cli.github.com/) (`gh auth
|
|
|
17
17
|
|
|
18
18
|
## Features
|
|
19
19
|
|
|
20
|
-
**Unified Dashboard** —
|
|
20
|
+
**Unified Dashboard** — GitHub issues from multiple repos and TickTick tasks in one view. Filter by repo, assignee, or backlog status.
|
|
21
21
|
|
|
22
22
|
**Interactive TUI** — Vim-style navigation (`j`/`k`), section collapsing, search (`/`), multi-select with bulk actions, and a detail panel on wide terminals.
|
|
23
23
|
|
|
24
|
-
**Issue Actions** — Pick up issues (`p`), assign/unassign (`a`/`u`), change status (`m`), comment (`c`), create issues (`n`) — all without leaving the terminal.
|
|
24
|
+
**Issue Actions** — Pick up issues (`p`), assign/unassign (`a`/`u`), change status (`m`), comment (`c`), create issues (`n`), add/remove labels (`l`) — all without leaving the terminal.
|
|
25
|
+
|
|
26
|
+
**Natural Language Issue Creation** — Press `I` and type `fix login bug #backend @alice due friday`. hog extracts the title, labels, assignee, and due date automatically. Optional LLM enhancement via OpenRouter.
|
|
27
|
+
|
|
28
|
+
**Multi-Line Comments** — Press `ctrl+e` in the comment overlay to open your `$EDITOR` (vim, nano, VS Code, etc.) for longer notes.
|
|
29
|
+
|
|
30
|
+
**Copy Link** — Press `y` to copy the selected issue's URL to your clipboard.
|
|
25
31
|
|
|
26
32
|
**Focus Mode** — Built-in Pomodoro timer (`f`). Lock onto an issue and focus for 25 minutes (configurable).
|
|
27
33
|
|
|
28
34
|
**Auto-Refresh** — Background refresh with age indicators (green/yellow/red) and failure tracking. Manual refresh with `r`.
|
|
29
35
|
|
|
30
|
-
**Toast Notifications** — Every async operation shows clear feedback. Errors persist with retry hints.
|
|
31
|
-
|
|
32
36
|
**Board Profiles** — Multiple board configurations for different contexts (work, personal, etc.).
|
|
33
37
|
|
|
34
38
|
**TickTick Optional** — Works with just GitHub. Enable TickTick integration when you want it.
|
|
@@ -40,20 +44,94 @@ Requires **Node.js 22+** and the [GitHub CLI](https://cli.github.com/) (`gh auth
|
|
|
40
44
|
| Key | Action |
|
|
41
45
|
|-----|--------|
|
|
42
46
|
| `j` / `k` | Navigate down / up |
|
|
47
|
+
| `↓` / `↑` | Navigate down / up |
|
|
43
48
|
| `Tab` / `Shift+Tab` | Next / previous section |
|
|
44
|
-
| `
|
|
45
|
-
| `
|
|
49
|
+
| `Space` | Toggle section (on header) or enter multi-select (on issue) |
|
|
50
|
+
| `Enter` | Open issue in browser (item) or toggle collapse (section) |
|
|
46
51
|
| `/` | Search |
|
|
52
|
+
| `n` | Create issue (form wizard) |
|
|
53
|
+
| `I` | Create issue from natural language |
|
|
47
54
|
| `p` | Pick issue (assign + sync to TickTick) |
|
|
48
55
|
| `a` / `u` | Assign / unassign |
|
|
49
|
-
| `m` | Change status |
|
|
50
|
-
| `
|
|
51
|
-
| `
|
|
52
|
-
| `
|
|
53
|
-
| `
|
|
54
|
-
|
|
|
56
|
+
| `m` | Change project status |
|
|
57
|
+
| `l` | Add / remove labels |
|
|
58
|
+
| `c` | Add comment |
|
|
59
|
+
| `ctrl+e` | Open `$EDITOR` for multi-line comment |
|
|
60
|
+
| `y` | Copy issue URL to clipboard |
|
|
61
|
+
| `f` | Focus mode (Pomodoro timer) |
|
|
62
|
+
| `C` | Collapse all sections |
|
|
63
|
+
| `r` / `R` | Refresh |
|
|
64
|
+
| `?` | Toggle help |
|
|
55
65
|
| `q` | Quit |
|
|
56
66
|
|
|
67
|
+
### Multi-Select
|
|
68
|
+
|
|
69
|
+
Press `Space` on any issue to enter multi-select mode, then:
|
|
70
|
+
|
|
71
|
+
| Key | Action |
|
|
72
|
+
|-----|--------|
|
|
73
|
+
| `Space` | Toggle item selection |
|
|
74
|
+
| `Enter` / `m` | Open bulk action menu |
|
|
75
|
+
| `Escape` | Clear selection and exit multi-select |
|
|
76
|
+
|
|
77
|
+
## Natural Language Issue Creation
|
|
78
|
+
|
|
79
|
+
Press `I` on the board to open the NL input. Type a description in plain English:
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
fix auth timeout on mobile #backend #bug @alice due friday
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
hog extracts:
|
|
86
|
+
- **Title** — `fix auth timeout on mobile`
|
|
87
|
+
- **Labels** — `backend`, `bug` (validated against repo labels)
|
|
88
|
+
- **Assignee** — `alice`
|
|
89
|
+
- **Due date** — parsed from `due friday`, `due end of month`, `due 2026-03-01`, etc.
|
|
90
|
+
|
|
91
|
+
A live preview shows the parsed fields before you confirm with `Enter`.
|
|
92
|
+
|
|
93
|
+
### Heuristic Tokens
|
|
94
|
+
|
|
95
|
+
These are extracted without any API key:
|
|
96
|
+
|
|
97
|
+
| Token | Example | Extracts |
|
|
98
|
+
|-------|---------|---------|
|
|
99
|
+
| `#word` | `#backend` | label |
|
|
100
|
+
| `@user` | `@alice` | assignee (`@me` → your GitHub login) |
|
|
101
|
+
| `due <expr>` | `due friday` | due date (chrono-node) |
|
|
102
|
+
|
|
103
|
+
Everything else becomes the title.
|
|
104
|
+
|
|
105
|
+
### LLM Enhancement (optional)
|
|
106
|
+
|
|
107
|
+
With an [OpenRouter](https://openrouter.ai) API key, hog sends ambiguous input to an LLM for richer title cleanup and inference. The heuristic tokens still take priority — LLM only fills gaps.
|
|
108
|
+
|
|
109
|
+
Set up during `hog init`, or any time with:
|
|
110
|
+
|
|
111
|
+
```sh
|
|
112
|
+
hog config ai:set-key sk-or-... # store key
|
|
113
|
+
hog config ai:clear-key # remove key
|
|
114
|
+
hog config ai:status # show active source
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Or set an environment variable (takes priority over the stored key):
|
|
118
|
+
|
|
119
|
+
```sh
|
|
120
|
+
export OPENROUTER_API_KEY=sk-or-...
|
|
121
|
+
# or
|
|
122
|
+
export ANTHROPIC_API_KEY=sk-ant-...
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Agent-Native: `hog issue create`
|
|
126
|
+
|
|
127
|
+
Create issues non-interactively from scripts or AI agents:
|
|
128
|
+
|
|
129
|
+
```sh
|
|
130
|
+
hog issue create "fix login bug #backend @alice due friday" --repo owner/repo
|
|
131
|
+
hog issue create "add dark mode" --repo owner/repo --dry-run # preview only
|
|
132
|
+
hog issue create "add dark mode" --repo owner/repo --json # structured output
|
|
133
|
+
```
|
|
134
|
+
|
|
57
135
|
## Commands
|
|
58
136
|
|
|
59
137
|
### `hog board`
|
|
@@ -69,6 +147,15 @@ hog board --repo myrepo --json # filter by repo
|
|
|
69
147
|
hog board --profile work --live # use a named profile
|
|
70
148
|
```
|
|
71
149
|
|
|
150
|
+
### `hog issue`
|
|
151
|
+
|
|
152
|
+
Manage issues from the command line.
|
|
153
|
+
|
|
154
|
+
```sh
|
|
155
|
+
hog issue create "fix login bug #backend due friday" --repo owner/repo
|
|
156
|
+
hog issue create "add dark mode" --repo owner/repo --dry-run
|
|
157
|
+
```
|
|
158
|
+
|
|
72
159
|
### `hog pick`
|
|
73
160
|
|
|
74
161
|
Assign a GitHub issue to yourself and create a linked TickTick task.
|
|
@@ -82,8 +169,8 @@ hog pick myrepo/145
|
|
|
82
169
|
Manage TickTick tasks directly.
|
|
83
170
|
|
|
84
171
|
```sh
|
|
85
|
-
hog task list
|
|
86
|
-
hog task add "Ship the feature"
|
|
172
|
+
hog task list
|
|
173
|
+
hog task add "Ship the feature"
|
|
87
174
|
hog task add "Bug fix" -p high -t "urgent"
|
|
88
175
|
hog task complete <taskId>
|
|
89
176
|
hog task update <taskId> --title "New title" -p medium
|
|
@@ -97,22 +184,31 @@ hog task use-project <projectId> # set default project
|
|
|
97
184
|
View and manage configuration.
|
|
98
185
|
|
|
99
186
|
```sh
|
|
100
|
-
hog config show
|
|
101
|
-
|
|
187
|
+
hog config show
|
|
188
|
+
|
|
189
|
+
# Repos
|
|
190
|
+
hog config repos
|
|
102
191
|
hog config repos:add owner/repo --project-number 1 --status-field-id PVTSSF_xxx --completion-type closeIssue
|
|
103
192
|
hog config repos:rm reponame
|
|
104
193
|
|
|
105
|
-
|
|
106
|
-
hog config ticktick:
|
|
194
|
+
# TickTick
|
|
195
|
+
hog config ticktick:enable
|
|
196
|
+
hog config ticktick:disable
|
|
197
|
+
|
|
198
|
+
# AI / natural language issue creation
|
|
199
|
+
hog config ai:set-key sk-or-... # store OpenRouter key
|
|
200
|
+
hog config ai:clear-key # remove stored key
|
|
201
|
+
hog config ai:status # show active source and provider
|
|
107
202
|
|
|
108
|
-
|
|
203
|
+
# Profiles
|
|
204
|
+
hog config profile:create work
|
|
109
205
|
hog config profile:delete work
|
|
110
|
-
hog config profile:default work
|
|
206
|
+
hog config profile:default work
|
|
111
207
|
```
|
|
112
208
|
|
|
113
209
|
### `hog init`
|
|
114
210
|
|
|
115
|
-
Interactive setup wizard. Detects your GitHub user,
|
|
211
|
+
Interactive setup wizard. Detects your GitHub user, picks repos, configures projects, and optionally sets up an OpenRouter key for AI-enhanced issue creation.
|
|
116
212
|
|
|
117
213
|
```sh
|
|
118
214
|
hog init # interactive setup
|
|
@@ -131,7 +227,7 @@ hog sync status # show sync mappings
|
|
|
131
227
|
|
|
132
228
|
## Configuration
|
|
133
229
|
|
|
134
|
-
Config lives at `~/.config/hog/config.json`. Created by `hog init` or manually.
|
|
230
|
+
Config lives at `~/.config/hog/config.json`. Created by `hog init` or edited manually.
|
|
135
231
|
|
|
136
232
|
```jsonc
|
|
137
233
|
{
|
|
@@ -150,25 +246,27 @@ Config lives at `~/.config/hog/config.json`. Created by `hog init` or manually.
|
|
|
150
246
|
"refreshInterval": 60, // seconds (min: 10)
|
|
151
247
|
"backlogLimit": 20,
|
|
152
248
|
"assignee": "your-github-username",
|
|
153
|
-
"focusDuration": 1500 // seconds (25 min)
|
|
249
|
+
"focusDuration": 1500 // seconds (25 min default)
|
|
154
250
|
},
|
|
155
251
|
"ticktick": {
|
|
156
252
|
"enabled": true // set false to use without TickTick
|
|
157
253
|
},
|
|
158
|
-
"profiles": {},
|
|
159
|
-
"defaultProfile": ""
|
|
254
|
+
"profiles": {},
|
|
255
|
+
"defaultProfile": ""
|
|
160
256
|
}
|
|
161
257
|
```
|
|
162
258
|
|
|
259
|
+
Credentials (TickTick OAuth token, OpenRouter API key) are stored separately in `~/.config/hog/auth.json` with `0600` permissions.
|
|
260
|
+
|
|
163
261
|
### Status Groups
|
|
164
262
|
|
|
165
|
-
By default, hog auto-detects status columns from your GitHub Project. Override per-repo
|
|
263
|
+
By default, hog auto-detects status columns from your GitHub Project. Override per-repo:
|
|
166
264
|
|
|
167
265
|
```json
|
|
168
266
|
"statusGroups": ["In Progress", "In Review", "Todo,Backlog"]
|
|
169
267
|
```
|
|
170
268
|
|
|
171
|
-
Each entry is a section. Comma-separated values merge into one section (header = first value). Terminal statuses (Done, Shipped, Closed, etc.) are always hidden.
|
|
269
|
+
Each entry is a board section. Comma-separated values merge into one section (header = first value). Terminal statuses (Done, Shipped, Closed, etc.) are always hidden.
|
|
172
270
|
|
|
173
271
|
### Profiles
|
|
174
272
|
|
|
@@ -185,6 +283,7 @@ hog board --profile personal --live
|
|
|
185
283
|
- **Node.js 22+**
|
|
186
284
|
- **GitHub CLI** (`gh`) — authenticated via `gh auth login`
|
|
187
285
|
- **TickTick account** — optional, for task sync
|
|
286
|
+
- **OpenRouter API key** — optional, for AI-enhanced issue creation (`hog config ai:set-key`)
|
|
188
287
|
|
|
189
288
|
## License
|
|
190
289
|
|
package/dist/cli.js
CHANGED
|
@@ -1222,8 +1222,8 @@ function useActions({
|
|
|
1222
1222
|
});
|
|
1223
1223
|
}, [toast, refresh]);
|
|
1224
1224
|
const handleCreateIssue = useCallback(
|
|
1225
|
-
async (repo, title, labels) => {
|
|
1226
|
-
const args = ["issue", "create", "--repo", repo, "--title", title];
|
|
1225
|
+
async (repo, title, body, labels) => {
|
|
1226
|
+
const args = ["issue", "create", "--repo", repo, "--title", title, "--body", body];
|
|
1227
1227
|
if (labels && labels.length > 0) {
|
|
1228
1228
|
for (const label of labels) {
|
|
1229
1229
|
args.push("--label", label);
|
|
@@ -2778,13 +2778,13 @@ function CreateIssueForm({
|
|
|
2778
2778
|
currentLabels: [],
|
|
2779
2779
|
labelCache: labelCache ?? {},
|
|
2780
2780
|
onConfirm: (addLabels) => {
|
|
2781
|
-
onSubmit(selectedRepo.name, title, addLabels.length > 0 ? addLabels : void 0);
|
|
2781
|
+
onSubmit(selectedRepo.name, title, "", addLabels.length > 0 ? addLabels : void 0);
|
|
2782
2782
|
},
|
|
2783
2783
|
onCancel: () => {
|
|
2784
|
-
onSubmit(selectedRepo.name, title);
|
|
2784
|
+
onSubmit(selectedRepo.name, title, "");
|
|
2785
2785
|
},
|
|
2786
2786
|
onError: () => {
|
|
2787
|
-
onSubmit(selectedRepo.name, title);
|
|
2787
|
+
onSubmit(selectedRepo.name, title, "");
|
|
2788
2788
|
}
|
|
2789
2789
|
}
|
|
2790
2790
|
)
|
|
@@ -2820,7 +2820,7 @@ function CreateIssueForm({
|
|
|
2820
2820
|
setTitle(trimmed);
|
|
2821
2821
|
setField("labels");
|
|
2822
2822
|
} else {
|
|
2823
|
-
onSubmit(selectedRepo.name, trimmed);
|
|
2823
|
+
onSubmit(selectedRepo.name, trimmed, "");
|
|
2824
2824
|
}
|
|
2825
2825
|
}
|
|
2826
2826
|
}
|
|
@@ -3018,8 +3018,12 @@ var init_help_overlay = __esm({
|
|
|
3018
3018
|
});
|
|
3019
3019
|
|
|
3020
3020
|
// src/board/components/nl-create-overlay.tsx
|
|
3021
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
3022
|
+
import { mkdtempSync as mkdtempSync2, readFileSync as readFileSync4, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "fs";
|
|
3023
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
3024
|
+
import { join as join4 } from "path";
|
|
3021
3025
|
import { Spinner as Spinner2, TextInput as TextInput3 } from "@inkjs/ui";
|
|
3022
|
-
import { Box as Box9, Text as Text9, useInput as useInput9 } from "ink";
|
|
3026
|
+
import { Box as Box9, Text as Text9, useInput as useInput9, useStdin as useStdin2 } from "ink";
|
|
3023
3027
|
import { useCallback as useCallback9, useEffect as useEffect5, useRef as useRef9, useState as useState9 } from "react";
|
|
3024
3028
|
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
3025
3029
|
function NlCreateOverlay({
|
|
@@ -3028,15 +3032,28 @@ function NlCreateOverlay({
|
|
|
3028
3032
|
labelCache,
|
|
3029
3033
|
onSubmit,
|
|
3030
3034
|
onCancel,
|
|
3035
|
+
onPauseRefresh,
|
|
3036
|
+
onResumeRefresh,
|
|
3031
3037
|
onLlmFallback
|
|
3032
3038
|
}) {
|
|
3033
3039
|
const [, setInput] = useState9("");
|
|
3034
3040
|
const [isParsing, setIsParsing] = useState9(false);
|
|
3035
3041
|
const [parsed, setParsed] = useState9(null);
|
|
3036
3042
|
const [parseError, setParseError] = useState9(null);
|
|
3037
|
-
const [
|
|
3043
|
+
const [step, setStep] = useState9("input");
|
|
3044
|
+
const [body, setBody] = useState9("");
|
|
3045
|
+
const [editingBody, setEditingBody] = useState9(false);
|
|
3038
3046
|
const submittedRef = useRef9(false);
|
|
3039
3047
|
const parseParamsRef = useRef9(null);
|
|
3048
|
+
const onSubmitRef = useRef9(onSubmit);
|
|
3049
|
+
const onCancelRef = useRef9(onCancel);
|
|
3050
|
+
const onPauseRef = useRef9(onPauseRefresh);
|
|
3051
|
+
const onResumeRef = useRef9(onResumeRefresh);
|
|
3052
|
+
onSubmitRef.current = onSubmit;
|
|
3053
|
+
onCancelRef.current = onCancel;
|
|
3054
|
+
onPauseRef.current = onPauseRefresh;
|
|
3055
|
+
onResumeRef.current = onResumeRefresh;
|
|
3056
|
+
const { setRawMode } = useStdin2();
|
|
3040
3057
|
const defaultRepoIdx = defaultRepoName ? Math.max(
|
|
3041
3058
|
0,
|
|
3042
3059
|
repos.findIndex((r) => r.name === defaultRepoName)
|
|
@@ -3044,19 +3061,19 @@ function NlCreateOverlay({
|
|
|
3044
3061
|
const [repoIdx, setRepoIdx] = useState9(defaultRepoIdx);
|
|
3045
3062
|
const selectedRepo = repos[repoIdx];
|
|
3046
3063
|
useInput9((inputChar, key) => {
|
|
3047
|
-
if (isParsing) return;
|
|
3064
|
+
if (isParsing || editingBody) return;
|
|
3048
3065
|
if (key.escape) {
|
|
3066
|
+
if (step === "body") {
|
|
3067
|
+
setStep("input");
|
|
3068
|
+
setParsed((p) => p);
|
|
3069
|
+
return;
|
|
3070
|
+
}
|
|
3049
3071
|
onCancel();
|
|
3050
3072
|
return;
|
|
3051
3073
|
}
|
|
3052
|
-
if (parsed) {
|
|
3074
|
+
if (parsed && step === "input") {
|
|
3053
3075
|
if (key.return) {
|
|
3054
|
-
|
|
3055
|
-
submittedRef.current = true;
|
|
3056
|
-
if (!selectedRepo) return;
|
|
3057
|
-
setCreateError(null);
|
|
3058
|
-
const labels = buildLabelList(parsed);
|
|
3059
|
-
onSubmit(selectedRepo.name, parsed.title, labels.length > 0 ? labels : void 0);
|
|
3076
|
+
setStep("body");
|
|
3060
3077
|
return;
|
|
3061
3078
|
}
|
|
3062
3079
|
if (inputChar === "r") {
|
|
@@ -3064,7 +3081,43 @@ function NlCreateOverlay({
|
|
|
3064
3081
|
return;
|
|
3065
3082
|
}
|
|
3066
3083
|
}
|
|
3084
|
+
if (step === "body" && inputChar === "") {
|
|
3085
|
+
setEditingBody(true);
|
|
3086
|
+
}
|
|
3067
3087
|
});
|
|
3088
|
+
useEffect5(() => {
|
|
3089
|
+
if (!editingBody) return;
|
|
3090
|
+
const editorEnv = process.env["VISUAL"] ?? process.env["EDITOR"] ?? "vi";
|
|
3091
|
+
const [cmd, ...extraArgs] = editorEnv.split(" ").filter(Boolean);
|
|
3092
|
+
if (!cmd) {
|
|
3093
|
+
setEditingBody(false);
|
|
3094
|
+
return;
|
|
3095
|
+
}
|
|
3096
|
+
let tmpDir = null;
|
|
3097
|
+
let tmpFile = null;
|
|
3098
|
+
try {
|
|
3099
|
+
onPauseRef.current?.();
|
|
3100
|
+
tmpDir = mkdtempSync2(join4(tmpdir2(), "hog-body-"));
|
|
3101
|
+
tmpFile = join4(tmpDir, "body.md");
|
|
3102
|
+
writeFileSync4(tmpFile, body);
|
|
3103
|
+
const inkInstance = getInkInstance();
|
|
3104
|
+
inkInstance?.clear();
|
|
3105
|
+
setRawMode(false);
|
|
3106
|
+
spawnSync2(cmd, [...extraArgs, tmpFile], { stdio: "inherit" });
|
|
3107
|
+
const content = readFileSync4(tmpFile, "utf-8");
|
|
3108
|
+
setRawMode(true);
|
|
3109
|
+
setBody(content.trimEnd());
|
|
3110
|
+
} finally {
|
|
3111
|
+
onResumeRef.current?.();
|
|
3112
|
+
if (tmpFile) {
|
|
3113
|
+
try {
|
|
3114
|
+
rmSync2(tmpDir, { recursive: true, force: true });
|
|
3115
|
+
} catch {
|
|
3116
|
+
}
|
|
3117
|
+
}
|
|
3118
|
+
setEditingBody(false);
|
|
3119
|
+
}
|
|
3120
|
+
}, [editingBody, body, setRawMode]);
|
|
3068
3121
|
const handleInputSubmit = useCallback9(
|
|
3069
3122
|
(text) => {
|
|
3070
3123
|
const trimmed = text.trim();
|
|
@@ -3103,6 +3156,45 @@ function NlCreateOverlay({
|
|
|
3103
3156
|
/* @__PURE__ */ jsx9(Spinner2, { label: "Parsing..." })
|
|
3104
3157
|
] });
|
|
3105
3158
|
}
|
|
3159
|
+
if (parsed && step === "body") {
|
|
3160
|
+
if (editingBody) {
|
|
3161
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
3162
|
+
/* @__PURE__ */ jsx9(Text9, { color: "cyan", bold: true, children: "\u2728 Creating Issue" }),
|
|
3163
|
+
/* @__PURE__ */ jsx9(Text9, { color: "cyan", children: "Opening editor for body\u2026" })
|
|
3164
|
+
] });
|
|
3165
|
+
}
|
|
3166
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
3167
|
+
/* @__PURE__ */ jsx9(Text9, { color: "cyan", bold: true, children: "\u2728 Creating Issue" }),
|
|
3168
|
+
/* @__PURE__ */ jsxs9(Box9, { children: [
|
|
3169
|
+
/* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "Title: " }),
|
|
3170
|
+
/* @__PURE__ */ jsx9(Text9, { children: parsed.title })
|
|
3171
|
+
] }),
|
|
3172
|
+
/* @__PURE__ */ jsxs9(Box9, { children: [
|
|
3173
|
+
/* @__PURE__ */ jsx9(Text9, { color: "cyan", children: "body: " }),
|
|
3174
|
+
/* @__PURE__ */ jsx9(
|
|
3175
|
+
TextInput3,
|
|
3176
|
+
{
|
|
3177
|
+
defaultValue: body,
|
|
3178
|
+
placeholder: "optional description (ctrl+e for editor)",
|
|
3179
|
+
onChange: setBody,
|
|
3180
|
+
onSubmit: (text) => {
|
|
3181
|
+
if (submittedRef.current) return;
|
|
3182
|
+
submittedRef.current = true;
|
|
3183
|
+
if (!selectedRepo) return;
|
|
3184
|
+
const labels = buildLabelList(parsed);
|
|
3185
|
+
onSubmitRef.current(
|
|
3186
|
+
selectedRepo.name,
|
|
3187
|
+
parsed.title,
|
|
3188
|
+
text.trim(),
|
|
3189
|
+
labels.length > 0 ? labels : void 0
|
|
3190
|
+
);
|
|
3191
|
+
}
|
|
3192
|
+
}
|
|
3193
|
+
)
|
|
3194
|
+
] }),
|
|
3195
|
+
/* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "Enter:create ctrl+e:editor Esc:back" })
|
|
3196
|
+
] });
|
|
3197
|
+
}
|
|
3106
3198
|
if (parsed) {
|
|
3107
3199
|
const labels = buildLabelList(parsed);
|
|
3108
3200
|
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
@@ -3132,8 +3224,7 @@ function NlCreateOverlay({
|
|
|
3132
3224
|
/* @__PURE__ */ jsx9(Text9, { children: formatDue(parsed.dueDate) })
|
|
3133
3225
|
] }) : null,
|
|
3134
3226
|
parsed.dueDate && selectedRepo && !hasDueLabelInCache(labelCache, selectedRepo.name) ? /* @__PURE__ */ jsx9(Text9, { color: "yellow", children: "\u26A0 No due:* label in this repo \u2014 will try to create label on submit" }) : null,
|
|
3135
|
-
|
|
3136
|
-
/* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "Enter:create Esc:cancel" })
|
|
3227
|
+
/* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "Enter:add body Esc:cancel" })
|
|
3137
3228
|
] });
|
|
3138
3229
|
}
|
|
3139
3230
|
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
@@ -3172,6 +3263,7 @@ var init_nl_create_overlay = __esm({
|
|
|
3172
3263
|
"src/board/components/nl-create-overlay.tsx"() {
|
|
3173
3264
|
"use strict";
|
|
3174
3265
|
init_ai();
|
|
3266
|
+
init_ink_instance();
|
|
3175
3267
|
}
|
|
3176
3268
|
});
|
|
3177
3269
|
|
|
@@ -3411,6 +3503,8 @@ function OverlayRenderer({
|
|
|
3411
3503
|
labelCache,
|
|
3412
3504
|
onSubmit: onCreateIssue,
|
|
3413
3505
|
onCancel: onExitOverlay,
|
|
3506
|
+
onPauseRefresh,
|
|
3507
|
+
onResumeRefresh,
|
|
3414
3508
|
onLlmFallback
|
|
3415
3509
|
}
|
|
3416
3510
|
) : null
|
|
@@ -3711,7 +3805,7 @@ var init_toast_container = __esm({
|
|
|
3711
3805
|
});
|
|
3712
3806
|
|
|
3713
3807
|
// src/board/components/dashboard.tsx
|
|
3714
|
-
import { execFileSync as execFileSync3, spawnSync as
|
|
3808
|
+
import { execFileSync as execFileSync3, spawnSync as spawnSync3 } from "child_process";
|
|
3715
3809
|
import { Spinner as Spinner4 } from "@inkjs/ui";
|
|
3716
3810
|
import { Box as Box16, Text as Text16, useApp, useStdout } from "ink";
|
|
3717
3811
|
import { useCallback as useCallback10, useEffect as useEffect6, useMemo as useMemo2, useRef as useRef11, useState as useState11 } from "react";
|
|
@@ -4046,8 +4140,8 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
4046
4140
|
const pendingPickRef = useRef11(null);
|
|
4047
4141
|
const labelCacheRef = useRef11({});
|
|
4048
4142
|
const handleCreateIssueWithPrompt = useCallback10(
|
|
4049
|
-
(repo, title, labels) => {
|
|
4050
|
-
actions.handleCreateIssue(repo, title, labels).then((result) => {
|
|
4143
|
+
(repo, title, body, labels) => {
|
|
4144
|
+
actions.handleCreateIssue(repo, title, body, labels).then((result) => {
|
|
4051
4145
|
if (result) {
|
|
4052
4146
|
pendingPickRef.current = result;
|
|
4053
4147
|
ui.enterConfirmPick();
|
|
@@ -4212,7 +4306,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
4212
4306
|
toast.info(`${label} \u2014 ${found.issue.url}`);
|
|
4213
4307
|
return;
|
|
4214
4308
|
}
|
|
4215
|
-
const result =
|
|
4309
|
+
const result = spawnSync3(cmd, args, {
|
|
4216
4310
|
input: found.issue.url,
|
|
4217
4311
|
stdio: ["pipe", "pipe", "pipe"]
|
|
4218
4312
|
});
|
|
@@ -5556,7 +5650,7 @@ function resolveProjectId(projectId) {
|
|
|
5556
5650
|
process.exit(1);
|
|
5557
5651
|
}
|
|
5558
5652
|
var program = new Command();
|
|
5559
|
-
program.name("hog").description("Personal command deck \u2014 unified task dashboard for GitHub Projects + TickTick").version("1.
|
|
5653
|
+
program.name("hog").description("Personal command deck \u2014 unified task dashboard for GitHub Projects + TickTick").version("1.5.0").option("--json", "Force JSON output").option("--human", "Force human-readable output").hook("preAction", (thisCommand) => {
|
|
5560
5654
|
const opts = thisCommand.opts();
|
|
5561
5655
|
if (opts.json) setFormat("json");
|
|
5562
5656
|
if (opts.human) setFormat("human");
|
|
@@ -5993,7 +6087,7 @@ issueCommand.command("create <text>").description("Create a GitHub issue from na
|
|
|
5993
6087
|
console.error("[dry-run] Skipping issue creation.");
|
|
5994
6088
|
return;
|
|
5995
6089
|
}
|
|
5996
|
-
const args = ["issue", "create", "--repo", repo, "--title", parsed.title];
|
|
6090
|
+
const args = ["issue", "create", "--repo", repo, "--title", parsed.title, "--body", ""];
|
|
5997
6091
|
for (const label of labels) {
|
|
5998
6092
|
args.push("--label", label);
|
|
5999
6093
|
}
|