@ondrej-svec/hog 1.12.0 → 1.14.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 +171 -106
- package/dist/cli.js +127 -60
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,121 +5,150 @@
|
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
6
|
[](https://nodejs.org)
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
**A lazygit-style terminal dashboard for GitHub Issues.** Keyboard-driven, single-line rows, no context switching.
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+

|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## What it does
|
|
15
|
+
|
|
16
|
+
`hog board --live` opens a five-panel TUI that shows all your GitHub Project issues across repos. Navigate with `j`/`k`, pick up issues, change statuses, comment, search, and open details — without ever touching a browser.
|
|
17
|
+
|
|
18
|
+
The layout is inspired by [lazygit](https://github.com/jesseduffield/lazygit): a narrow left column for repos and statuses, a wide issues list in the middle, a detail panel on the right, and an activity feed at the bottom.
|
|
19
|
+
|
|
20
|
+
---
|
|
12
21
|
|
|
13
22
|
## Quick Start
|
|
14
23
|
|
|
15
24
|
```sh
|
|
16
25
|
npm install -g @ondrej-svec/hog
|
|
17
|
-
hog init # interactive setup
|
|
26
|
+
hog init # interactive setup (picks up gh auth automatically)
|
|
18
27
|
hog board --live
|
|
19
28
|
```
|
|
20
29
|
|
|
21
|
-
|
|
30
|
+
**Requirements:** [Node.js 22+](https://nodejs.org) and the [GitHub CLI](https://cli.github.com/) authenticated via `gh auth login`.
|
|
22
31
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
**Unified Dashboard** — GitHub issues from multiple repos and TickTick tasks in one view. Filter by repo, assignee, or backlog status.
|
|
32
|
+
---
|
|
26
33
|
|
|
27
|
-
|
|
34
|
+
## Panel Layout
|
|
28
35
|
|
|
29
|
-
|
|
36
|
+
```
|
|
37
|
+
┌──────────────┬─────────────────────────────────┬──────────────────┐
|
|
38
|
+
│ [1] Repos │ [3] Issues │ [0] Detail │
|
|
39
|
+
│ [2] Statuses │ (main panel, full issue list) │ (selected item) │
|
|
40
|
+
└──────────────┴─────────────────────────────────┴──────────────────┘
|
|
41
|
+
│ [4] Activity │
|
|
42
|
+
└────────────────────────────────────────────────────────────────────┘
|
|
43
|
+
```
|
|
30
44
|
|
|
31
|
-
|
|
45
|
+
Switch between panels with `0`–`4`. The detail panel and activity feed only appear on wider terminals (≥120 cols and ≥140 cols respectively).
|
|
32
46
|
|
|
33
|
-
|
|
47
|
+
---
|
|
34
48
|
|
|
35
|
-
|
|
49
|
+
## Features
|
|
36
50
|
|
|
37
|
-
|
|
51
|
+
### Issue list
|
|
38
52
|
|
|
39
|
-
|
|
53
|
+
Each issue fits on a single line with fixed-width columns:
|
|
40
54
|
|
|
41
|
-
|
|
55
|
+
```
|
|
56
|
+
▶ #199 Frontend ↔ Backend integration spec… [M] [p:H] unassigned 3d
|
|
57
|
+
#205 UI elements displaying in Cz… [M] [p:H] unassigned 1d
|
|
58
|
+
```
|
|
42
59
|
|
|
43
|
-
|
|
60
|
+
| Column | Width | Content |
|
|
61
|
+
|--------|-------|---------|
|
|
62
|
+
| Cursor | 2 | `▶` when selected |
|
|
63
|
+
| Number | 7 | `#1234` |
|
|
64
|
+
| Title | dynamic | truncated to fit panel width |
|
|
65
|
+
| Labels | 13 | up to 2 compact abbreviations: `[bug]`, `[p:H]`, `[M]`, `[WIP]` |
|
|
66
|
+
| Assignee | 10 | login or `unassigned` |
|
|
67
|
+
| Date | 10 | target date (`today`, `in 4d`, `3d overdue`) or age (`2h`, `5m`) |
|
|
44
68
|
|
|
45
|
-
|
|
69
|
+
Labels are abbreviated automatically: `size:M` → `[M]`, `priority:high` → `[p:H]`, `work:*` → `[WIP]`, `enhancement` → `[enh]`.
|
|
46
70
|
|
|
47
|
-
|
|
71
|
+
### Navigation
|
|
48
72
|
|
|
49
73
|
| Key | Action |
|
|
50
74
|
|-----|--------|
|
|
51
|
-
| `j` / `k` |
|
|
52
|
-
| `↓` / `↑` |
|
|
75
|
+
| `j` / `k` | Down / up |
|
|
76
|
+
| `↓` / `↑` | Down / up |
|
|
53
77
|
| `Tab` / `Shift+Tab` | Next / previous section |
|
|
54
|
-
| `
|
|
55
|
-
| `
|
|
56
|
-
|
|
|
57
|
-
| `
|
|
58
|
-
| `
|
|
59
|
-
|
|
|
60
|
-
| `
|
|
78
|
+
| `0`–`4` | Jump to panel |
|
|
79
|
+
| `Space` | Toggle section collapse (on header) or enter multi-select (on issue) |
|
|
80
|
+
| `Enter` | Open in browser (issue) or toggle collapse (section) |
|
|
81
|
+
| `0` | Detail panel — full-screen overlay on narrow terminals, focus side panel on wide |
|
|
82
|
+
| `C` | Collapse all sections |
|
|
83
|
+
| `?` | Toggle help overlay |
|
|
84
|
+
| `q` | Quit |
|
|
85
|
+
|
|
86
|
+
### Issue actions
|
|
87
|
+
|
|
88
|
+
| Key | Action |
|
|
89
|
+
|-----|--------|
|
|
90
|
+
| `p` | Pick up issue — assign to yourself + optional TickTick task |
|
|
91
|
+
| `a` / `u` | Assign / unassign collaborator |
|
|
61
92
|
| `m` | Change project status |
|
|
62
93
|
| `l` | Add / remove labels |
|
|
63
94
|
| `c` | Add comment |
|
|
64
|
-
| `ctrl+e` | Open `$EDITOR` for multi-line comment |
|
|
95
|
+
| `ctrl+e` | Open `$EDITOR` for a multi-line comment |
|
|
65
96
|
| `y` | Copy issue URL to clipboard |
|
|
97
|
+
| `n` | Create issue (form wizard) |
|
|
98
|
+
| `I` | Create issue from natural language |
|
|
66
99
|
| `f` | Focus mode (Pomodoro timer) |
|
|
67
|
-
| `C` | Collapse all sections |
|
|
68
|
-
| `r` / `R` | Refresh |
|
|
69
|
-
| `?` | Toggle help |
|
|
70
|
-
| `q` | Quit |
|
|
71
100
|
|
|
72
|
-
###
|
|
101
|
+
### Board controls
|
|
102
|
+
|
|
103
|
+
| Key | Action |
|
|
104
|
+
|-----|--------|
|
|
105
|
+
| `/` | Search issues by title |
|
|
106
|
+
| `r` / `R` | Refresh now |
|
|
73
107
|
|
|
74
|
-
|
|
108
|
+
### Multi-select
|
|
109
|
+
|
|
110
|
+
Press `Space` on any issue to enter multi-select, then:
|
|
75
111
|
|
|
76
112
|
| Key | Action |
|
|
77
113
|
|-----|--------|
|
|
78
|
-
| `Space` | Toggle item
|
|
79
|
-
| `Enter` / `m` |
|
|
80
|
-
| `Escape` |
|
|
114
|
+
| `Space` | Toggle item |
|
|
115
|
+
| `Enter` / `m` | Bulk action menu (status, assign, label) |
|
|
116
|
+
| `Escape` | Exit multi-select |
|
|
117
|
+
|
|
118
|
+
Multi-select is constrained to a single repo (GitHub API requirement).
|
|
119
|
+
|
|
120
|
+
---
|
|
81
121
|
|
|
82
122
|
## Natural Language Issue Creation
|
|
83
123
|
|
|
84
|
-
Press `I`
|
|
124
|
+
Press `I` to open the natural language input. Type a plain-English description:
|
|
85
125
|
|
|
86
126
|
```
|
|
87
127
|
fix auth timeout on mobile #backend #bug @alice due friday
|
|
88
128
|
```
|
|
89
129
|
|
|
90
130
|
hog extracts:
|
|
91
|
-
- **Title** — `fix auth timeout on mobile`
|
|
92
|
-
- **Labels** — `backend`, `bug` (validated against repo labels)
|
|
93
|
-
- **Assignee** — `alice`
|
|
94
|
-
- **Due date** — parsed from `due friday`, `due end of month`, `due 2026-03-01`, etc.
|
|
95
|
-
|
|
96
|
-
A live preview shows the parsed fields before you confirm with `Enter`.
|
|
97
|
-
|
|
98
|
-
### Heuristic Tokens
|
|
99
|
-
|
|
100
|
-
These are extracted without any API key:
|
|
101
131
|
|
|
102
|
-
|
|
|
103
|
-
|
|
104
|
-
| `#word` | `#backend` |
|
|
105
|
-
| `@user` | `@alice
|
|
106
|
-
| `due <expr>` | `due friday`
|
|
132
|
+
| Field | Token | Example |
|
|
133
|
+
|-------|-------|---------|
|
|
134
|
+
| Labels | `#word` | `#backend`, `#bug` |
|
|
135
|
+
| Assignee | `@user` | `@alice`, `@me` |
|
|
136
|
+
| Due date | `due <expr>` | `due friday`, `due end of month`, `due 2026-03-01` |
|
|
137
|
+
| Title | everything else | `fix auth timeout on mobile` |
|
|
107
138
|
|
|
108
|
-
|
|
139
|
+
A live preview shows the parsed fields before you confirm with `Enter`. Labels are validated against the repo's actual label list.
|
|
109
140
|
|
|
110
|
-
### LLM
|
|
141
|
+
### LLM enhancement (optional)
|
|
111
142
|
|
|
112
|
-
With an [OpenRouter](https://openrouter.ai) API key, hog sends ambiguous input to an LLM for richer title cleanup
|
|
113
|
-
|
|
114
|
-
Set up during `hog init`, or any time with:
|
|
143
|
+
With an [OpenRouter](https://openrouter.ai) API key, hog sends ambiguous input to an LLM for richer title cleanup. Heuristic tokens always take priority — LLM only fills gaps.
|
|
115
144
|
|
|
116
145
|
```sh
|
|
117
146
|
hog config ai:set-key sk-or-... # store key
|
|
118
|
-
hog config ai:clear-key # remove
|
|
119
|
-
hog config ai:status # show active
|
|
147
|
+
hog config ai:clear-key # remove
|
|
148
|
+
hog config ai:status # show active provider
|
|
120
149
|
```
|
|
121
150
|
|
|
122
|
-
Or
|
|
151
|
+
Or use environment variables (take priority over stored key):
|
|
123
152
|
|
|
124
153
|
```sh
|
|
125
154
|
export OPENROUTER_API_KEY=sk-or-...
|
|
@@ -127,51 +156,40 @@ export OPENROUTER_API_KEY=sk-or-...
|
|
|
127
156
|
export ANTHROPIC_API_KEY=sk-ant-...
|
|
128
157
|
```
|
|
129
158
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
Create issues non-interactively from scripts or AI agents:
|
|
133
|
-
|
|
134
|
-
```sh
|
|
135
|
-
hog issue create "fix login bug #backend @alice due friday" --repo owner/repo
|
|
136
|
-
hog issue create "add dark mode" --repo owner/repo --dry-run # preview only
|
|
137
|
-
hog issue create "add dark mode" --repo owner/repo --json # structured output
|
|
138
|
-
```
|
|
159
|
+
---
|
|
139
160
|
|
|
140
161
|
## Commands
|
|
141
162
|
|
|
142
163
|
### `hog board`
|
|
143
164
|
|
|
144
|
-
Open the unified task dashboard.
|
|
145
|
-
|
|
146
165
|
```sh
|
|
147
|
-
hog board --live # interactive TUI
|
|
148
|
-
hog board --json # full board
|
|
149
|
-
hog board --mine --json # only my assigned issues
|
|
166
|
+
hog board --live # interactive TUI
|
|
167
|
+
hog board --json # full board as JSON
|
|
168
|
+
hog board --mine --json # only my assigned issues
|
|
150
169
|
hog board --backlog --json # only unassigned issues
|
|
151
|
-
hog board --repo
|
|
170
|
+
hog board --repo owner/repo --json # filter by repo
|
|
152
171
|
hog board --profile work --live # use a named profile
|
|
153
172
|
```
|
|
154
173
|
|
|
155
174
|
### `hog issue`
|
|
156
175
|
|
|
157
|
-
Manage issues from the command line.
|
|
158
|
-
|
|
159
176
|
```sh
|
|
160
177
|
hog issue create "fix login bug #backend due friday" --repo owner/repo
|
|
161
|
-
hog issue create "add dark mode" --repo owner/repo --dry-run
|
|
178
|
+
hog issue create "add dark mode" --repo owner/repo --dry-run # preview
|
|
179
|
+
hog issue create "add dark mode" --repo owner/repo --json # structured output
|
|
162
180
|
```
|
|
163
181
|
|
|
164
182
|
### `hog pick`
|
|
165
183
|
|
|
166
|
-
Assign
|
|
184
|
+
Assign an issue to yourself and optionally create a linked TickTick task.
|
|
167
185
|
|
|
168
186
|
```sh
|
|
169
|
-
hog pick
|
|
187
|
+
hog pick owner/repo/145
|
|
170
188
|
```
|
|
171
189
|
|
|
172
190
|
### `hog task`
|
|
173
191
|
|
|
174
|
-
Manage TickTick tasks
|
|
192
|
+
Manage TickTick tasks (requires TickTick to be enabled).
|
|
175
193
|
|
|
176
194
|
```sh
|
|
177
195
|
hog task list
|
|
@@ -186,8 +204,6 @@ hog task use-project <projectId> # set default project
|
|
|
186
204
|
|
|
187
205
|
### `hog config`
|
|
188
206
|
|
|
189
|
-
View and manage configuration.
|
|
190
|
-
|
|
191
207
|
```sh
|
|
192
208
|
hog config show
|
|
193
209
|
|
|
@@ -200,10 +216,10 @@ hog config repos:rm reponame
|
|
|
200
216
|
hog config ticktick:enable
|
|
201
217
|
hog config ticktick:disable
|
|
202
218
|
|
|
203
|
-
# AI
|
|
204
|
-
hog config ai:set-key sk-or-...
|
|
205
|
-
hog config ai:clear-key
|
|
206
|
-
hog config ai:status
|
|
219
|
+
# AI
|
|
220
|
+
hog config ai:set-key sk-or-...
|
|
221
|
+
hog config ai:clear-key
|
|
222
|
+
hog config ai:status
|
|
207
223
|
|
|
208
224
|
# Profiles
|
|
209
225
|
hog config profile:create work
|
|
@@ -213,26 +229,28 @@ hog config profile:default work
|
|
|
213
229
|
|
|
214
230
|
### `hog init`
|
|
215
231
|
|
|
216
|
-
Interactive setup
|
|
232
|
+
Interactive setup. Detects your GitHub user, discovers your repos and project IDs, and optionally configures TickTick and an AI key.
|
|
217
233
|
|
|
218
234
|
```sh
|
|
219
|
-
hog init #
|
|
235
|
+
hog init # first-time setup
|
|
220
236
|
hog init --force # overwrite existing config
|
|
221
237
|
```
|
|
222
238
|
|
|
223
239
|
### `hog sync`
|
|
224
240
|
|
|
225
|
-
Sync GitHub
|
|
241
|
+
Sync GitHub issue status with TickTick task completion.
|
|
226
242
|
|
|
227
243
|
```sh
|
|
228
244
|
hog sync run # run sync
|
|
229
|
-
hog sync run --dry-run # preview
|
|
230
|
-
hog sync status # show
|
|
245
|
+
hog sync run --dry-run # preview
|
|
246
|
+
hog sync status # show current mappings
|
|
231
247
|
```
|
|
232
248
|
|
|
249
|
+
---
|
|
250
|
+
|
|
233
251
|
## Configuration
|
|
234
252
|
|
|
235
|
-
Config
|
|
253
|
+
Config: `~/.config/hog/config.json` (created by `hog init`, schema version 3).
|
|
236
254
|
|
|
237
255
|
```jsonc
|
|
238
256
|
{
|
|
@@ -244,38 +262,38 @@ Config lives at `~/.config/hog/config.json`. Created by `hog init` or edited man
|
|
|
244
262
|
"projectNumber": 1,
|
|
245
263
|
"statusFieldId": "PVTSSF_xxx",
|
|
246
264
|
"completionAction": { "type": "closeIssue" },
|
|
247
|
-
"statusGroups": ["In Progress", "Todo,Backlog"] // optional
|
|
265
|
+
"statusGroups": ["In Progress", "In Review", "Todo,Backlog"] // optional
|
|
248
266
|
}
|
|
249
267
|
],
|
|
250
268
|
"board": {
|
|
251
|
-
"refreshInterval": 60, // seconds (min
|
|
269
|
+
"refreshInterval": 60, // seconds (min 10)
|
|
252
270
|
"backlogLimit": 20,
|
|
253
|
-
"assignee": "your-github-
|
|
271
|
+
"assignee": "your-github-login",
|
|
254
272
|
"focusDuration": 1500 // seconds (25 min default)
|
|
255
273
|
},
|
|
256
274
|
"ticktick": {
|
|
257
|
-
"enabled":
|
|
275
|
+
"enabled": false // set true to enable TickTick sync
|
|
258
276
|
},
|
|
259
277
|
"profiles": {},
|
|
260
278
|
"defaultProfile": ""
|
|
261
279
|
}
|
|
262
280
|
```
|
|
263
281
|
|
|
264
|
-
Credentials (TickTick OAuth token, OpenRouter
|
|
282
|
+
Credentials (TickTick OAuth token, OpenRouter key) live in `~/.config/hog/auth.json` with `0600` permissions.
|
|
265
283
|
|
|
266
|
-
### Status
|
|
284
|
+
### Status groups
|
|
267
285
|
|
|
268
|
-
|
|
286
|
+
hog auto-detects status columns from your GitHub Project. Override per-repo with `statusGroups`:
|
|
269
287
|
|
|
270
288
|
```json
|
|
271
289
|
"statusGroups": ["In Progress", "In Review", "Todo,Backlog"]
|
|
272
290
|
```
|
|
273
291
|
|
|
274
|
-
Each entry
|
|
292
|
+
Each entry becomes a board section. Comma-separated values merge into one section (header = first value). Terminal statuses (Done, Shipped, Closed, etc.) are always hidden.
|
|
275
293
|
|
|
276
294
|
### Profiles
|
|
277
295
|
|
|
278
|
-
|
|
296
|
+
Switch board configs for different contexts:
|
|
279
297
|
|
|
280
298
|
```sh
|
|
281
299
|
hog config profile:create work
|
|
@@ -283,12 +301,59 @@ hog config profile:default work
|
|
|
283
301
|
hog board --profile personal --live
|
|
284
302
|
```
|
|
285
303
|
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
## Agent-friendly
|
|
307
|
+
|
|
308
|
+
Every command supports `--json` for structured output. This makes hog scriptable and usable by AI agents:
|
|
309
|
+
|
|
310
|
+
```sh
|
|
311
|
+
hog board --mine --json | jq '.issues[] | select(.labels[] | .name == "bug")'
|
|
312
|
+
hog issue create "fix login bug #backend @alice due friday" --repo owner/repo --json
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
## How it works
|
|
318
|
+
|
|
319
|
+
- **GitHub data** — always synchronous via `execFileSync("gh", ...)`. No GitHub tokens or REST API calls; `gh` CLI handles auth.
|
|
320
|
+
- **TickTick data** — async HTTP via the TickTick Open API. OAuth token stored in `auth.json`.
|
|
321
|
+
- **Rendering** — [Ink](https://github.com/vadimdemedes/ink) (React for CLIs). Each panel is an Ink component; rows are pre-truncated in JS so Ink never wraps text.
|
|
322
|
+
- **Auto-refresh** — `setInterval` re-fetches in the background; age indicator turns yellow (>2 min) then red (>5 min).
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
## Contributing
|
|
327
|
+
|
|
328
|
+
```sh
|
|
329
|
+
git clone https://github.com/ondrej-svec/hog
|
|
330
|
+
cd hog
|
|
331
|
+
npm install
|
|
332
|
+
npm run dev -- board --live # run from source
|
|
333
|
+
npm run test # vitest
|
|
334
|
+
npm run ci # typecheck + lint + tests (what CI runs)
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
**Toolchain:** TypeScript (strict), [Biome](https://biomejs.dev/) for lint/format, [tsup](https://tsup.egoist.dev/) for bundling, [Vitest](https://vitest.dev/) for tests. 80% coverage threshold enforced.
|
|
338
|
+
|
|
339
|
+
Filenames must be `kebab-case`. `noExplicitAny` is an error. Use `import type` for type-only imports.
|
|
340
|
+
|
|
341
|
+
Run a single test file:
|
|
342
|
+
|
|
343
|
+
```sh
|
|
344
|
+
npx vitest run src/board/components/issue-row.test.tsx
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
286
349
|
## Requirements
|
|
287
350
|
|
|
288
351
|
- **Node.js 22+**
|
|
289
352
|
- **GitHub CLI** (`gh`) — authenticated via `gh auth login`
|
|
290
|
-
- **TickTick account** — optional
|
|
291
|
-
- **OpenRouter API key** — optional, for AI-enhanced issue creation
|
|
353
|
+
- **TickTick account** — optional
|
|
354
|
+
- **OpenRouter API key** — optional, for AI-enhanced issue creation
|
|
355
|
+
|
|
356
|
+
---
|
|
292
357
|
|
|
293
358
|
## License
|
|
294
359
|
|