@drazenbebic/wdid 0.1.3 → 0.3.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 +134 -21
- package/dist/index.js +1110 -32
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
<picture>
|
|
3
|
+
<source
|
|
4
|
+
srcset="./logos/wdid_logo_white_transparent.png"
|
|
5
|
+
media="(prefers-color-scheme: dark)"
|
|
6
|
+
width="820" height="332"
|
|
7
|
+
/>
|
|
8
|
+
<img
|
|
9
|
+
src="./logos/wdid_logo_black_transparent.png"
|
|
10
|
+
alt="What did I do Logo"
|
|
11
|
+
width="820" height="332"
|
|
12
|
+
/>
|
|
13
|
+
</picture>
|
|
14
|
+
</div>
|
|
2
15
|
|
|
3
16
|
> What did I do? — a small CLI that summarizes your git activity as a tidy table, so you can fill in your timesheet without trying to remember Tuesday.
|
|
4
17
|
|
|
5
|
-
`wdid` reads `git log` for your author across one or more repos and renders the output as a colorized table with **Date
|
|
18
|
+
`wdid` reads `git log` for your author across one or more repos and renders the output as a colorized table with **Date** (with commit time, shown in your local timezone), **Ticket** (JIRA-style `ABC-123` by default, parsed from the commit subject), and **Description**.
|
|
6
19
|
|
|
7
20
|
## Install
|
|
8
21
|
|
|
@@ -28,17 +41,36 @@ By default `wdid` uses `git config user.name` as the author and the current work
|
|
|
28
41
|
### Example output
|
|
29
42
|
|
|
30
43
|
```
|
|
31
|
-
|
|
32
|
-
│ Date
|
|
33
|
-
|
|
34
|
-
│ 2026-05-27 │ ABC-123 │ feat(ABC-123): add login flow │
|
|
35
|
-
│ 2026-05-27 │ — │ chore: bump deps │
|
|
36
|
-
│ 2026-05-26 │ ABC-119 │ fix(ABC-119): handle empty payload │
|
|
37
|
-
|
|
44
|
+
┌──────────────────┬──────────────┬──────────────────────────────────────────────────┐
|
|
45
|
+
│ Date │ Ticket │ Description │
|
|
46
|
+
├──────────────────┼──────────────┼──────────────────────────────────────────────────┤
|
|
47
|
+
│ 2026-05-27 16:42 │ ABC-123 │ feat(ABC-123): add login flow │
|
|
48
|
+
│ 2026-05-27 11:08 │ — │ chore: bump deps │
|
|
49
|
+
│ 2026-05-26 17:53 │ ABC-119 │ fix(ABC-119): handle empty payload │
|
|
50
|
+
└──────────────────┴──────────────┴──────────────────────────────────────────────────┘
|
|
38
51
|
```
|
|
39
52
|
|
|
53
|
+
The time is rendered dimmed and shown in your local timezone (parsed from the committer's full ISO timestamp).
|
|
54
|
+
|
|
40
55
|
If a commit doesn't reference a ticket, the Ticket column is left blank (rendered as `—`).
|
|
41
56
|
|
|
57
|
+
With `--group-by-day`, the date moves into a section heading instead of repeating per row, making longer outputs feel more like a journal:
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
┌───────┬──────────────┬─────────────────────────────────────┐
|
|
61
|
+
│ Time │ Ticket │ Description │
|
|
62
|
+
├───────┴──────────────┴─────────────────────────────────────┤
|
|
63
|
+
│ 2026-05-27 │
|
|
64
|
+
├───────┬──────────────┬─────────────────────────────────────┤
|
|
65
|
+
│ 16:42 │ ABC-123 │ feat(ABC-123): add login flow │
|
|
66
|
+
│ 11:08 │ — │ chore: bump deps │
|
|
67
|
+
├───────┴──────────────┴─────────────────────────────────────┤
|
|
68
|
+
│ 2026-05-26 │
|
|
69
|
+
├───────┬──────────────┬─────────────────────────────────────┤
|
|
70
|
+
│ 17:53 │ ABC-119 │ fix(ABC-119): handle empty payload │
|
|
71
|
+
└───────┴──────────────┴─────────────────────────────────────┘
|
|
72
|
+
```
|
|
73
|
+
|
|
42
74
|
## Options
|
|
43
75
|
|
|
44
76
|
| Option | Description |
|
|
@@ -50,6 +82,10 @@ If a commit doesn't reference a ticket, the Ticket column is left blank (rendere
|
|
|
50
82
|
| `--repo <path...>` | One or more repo paths to query. Defaults to `defaultRepos` in config, then the current dir. |
|
|
51
83
|
| `--format <preset>` | Ticket format: `jira`, `github`, `conventional`, or `custom`. Defaults to `jira`. |
|
|
52
84
|
| `--ticket-pattern <regex>` | Custom regex for ticket extraction. Implies `--format custom`; overrides `--format`. |
|
|
85
|
+
| `--no-color` | Disable colored output. Also honored via the `NO_COLOR` env var. |
|
|
86
|
+
| `--limit <N>` | Cap the table to the most recent `N` rows. Positive integer. |
|
|
87
|
+
| `--group-by-day` | Group rows under a bold date heading per day; the row only shows the time. |
|
|
88
|
+
| `--json` | Emit a JSON array of commit entries to stdout instead of the table. Empty result is `[]`. |
|
|
53
89
|
|
|
54
90
|
## Configuration
|
|
55
91
|
|
|
@@ -71,21 +107,98 @@ CLI flags always win. The first match in this list is used in full (configs do n
|
|
|
71
107
|
}
|
|
72
108
|
```
|
|
73
109
|
|
|
74
|
-
| Field
|
|
75
|
-
|
|
|
76
|
-
| `format`
|
|
77
|
-
| `customPattern`
|
|
78
|
-
| `defaultAuthor`
|
|
79
|
-
| `defaultRepos`
|
|
110
|
+
| Field | Type | Description |
|
|
111
|
+
| ------------------- | -------------------------------------------------- | ---------------------------------------------------------------------------------- |
|
|
112
|
+
| `format` | `"jira" \| "github" \| "conventional" \| "custom"` | Ticket extraction preset. Default `jira`. |
|
|
113
|
+
| `customPattern` | `string` | Regex used when `format` is `"custom"`. First capture group wins, else full match. |
|
|
114
|
+
| `defaultAuthor` | `string` | Used when `--author` is not passed and you want to skip the `git config` lookup. |
|
|
115
|
+
| `defaultRepos` | `string[]` | Paths to query when no `--repo` is given. `~` is expanded. |
|
|
116
|
+
| `ticketColumnLabel` | `string` | Override the auto-picked column header (see below). |
|
|
80
117
|
|
|
81
118
|
### Format presets
|
|
82
119
|
|
|
83
|
-
| Preset | Matches | Example commit →
|
|
84
|
-
| -------------- | ------------------------------------------------ | -------------------------------------- |
|
|
85
|
-
| `jira` | `ABC-123` style (uppercase project key + digits) | `feat(ABC-123): add login` → `ABC-123` |
|
|
86
|
-
| `github` | `#123` style | `Closes #42` → `42` |
|
|
87
|
-
| `conventional` | Conventional Commit `type(scope)!` | `feat(auth)!: ...` → `feat(auth)!` |
|
|
88
|
-
| `custom` | Your `customPattern` regex | depends on the regex |
|
|
120
|
+
| Preset | Matches | Example commit → match | Column header |
|
|
121
|
+
| -------------- | ------------------------------------------------ | -------------------------------------- | ------------- |
|
|
122
|
+
| `jira` | `ABC-123` style (uppercase project key + digits) | `feat(ABC-123): add login` → `ABC-123` | `Ticket` |
|
|
123
|
+
| `github` | `#123` style | `Closes #42` → `42` | `Issue` |
|
|
124
|
+
| `conventional` | Conventional Commit `type(scope)!` | `feat(auth)!: ...` → `feat(auth)!` | `Type` |
|
|
125
|
+
| `custom` | Your `customPattern` regex | depends on the regex | `Match` |
|
|
126
|
+
|
|
127
|
+
The column header is picked automatically based on the active format. To override it for a specific preset (e.g. call them "Tasks" instead of "Ticket"), set `ticketColumnLabel` in your config.
|
|
128
|
+
|
|
129
|
+
## Toggl integration
|
|
130
|
+
|
|
131
|
+
`wdid toggl sync [date]` pushes the day's commits to Toggl as time entries. By default, commits with the same ticket are **collapsed into a single entry** (duration scales with commit count) and commits whose subject matches `\bmerge\b` are skipped. Entries stack from a configurable day-start hour — you adjust the exact times in Toggl yourself. The sync is **idempotent**: each entry's description carries one `(wdid <short-sha>)` marker per included commit, and re-running skips commits already pushed.
|
|
132
|
+
|
|
133
|
+
Descriptions are condensed for Toggl: the conventional-commit prefix (`feat:`, `chore(ABC-123):`, `fix!:`, etc.) is stripped, and the ticket — if any — is prepended once. So `chore(EN-4435): remove requestBody` becomes `EN-4435: remove requestBody`. Aggregated entries look like `EN-4435: subject A; subject B; subject C`.
|
|
134
|
+
|
|
135
|
+
```sh
|
|
136
|
+
wdid toggl sync # push today
|
|
137
|
+
wdid toggl sync 2026-05-27 # push a specific day
|
|
138
|
+
wdid toggl sync today --dry-run # preview without pushing
|
|
139
|
+
wdid toggl sync --workspace 12345 today # override the configured workspace
|
|
140
|
+
wdid toggl sync --from 2026-05-25 --to 2026-05-27 # push a multi-day range (inclusive)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
`--from` and `--to` are inclusive and mutually exclusive with the positional `[date]`. Each day is planned independently (its own 09:00 start, its own dedup fetch). On a per-day failure (Toggl 500, missing project, etc.), the sync continues through the remaining days and exits non-zero with a summary so one bad day doesn't strand the rest. The range is capped at 366 days as a guardrail.
|
|
144
|
+
|
|
145
|
+
### Toggl config
|
|
146
|
+
|
|
147
|
+
Add these alongside the other config fields:
|
|
148
|
+
|
|
149
|
+
```json
|
|
150
|
+
{
|
|
151
|
+
"togglApiToken": "your-api-token",
|
|
152
|
+
"togglWorkspaceId": 12345,
|
|
153
|
+
"togglProjects": {
|
|
154
|
+
"ABC-": 67890,
|
|
155
|
+
"DEF-": 67891
|
|
156
|
+
},
|
|
157
|
+
"togglDefaultProjectId": 99999,
|
|
158
|
+
"togglDefaultDurationMinutes": 30,
|
|
159
|
+
"togglDayStartHour": 9,
|
|
160
|
+
"togglOneEntryPerTicket": true,
|
|
161
|
+
"togglIgnoreSubjectPattern": "\\bmerge\\b"
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
| Field | Type | Description |
|
|
166
|
+
| ----------------------------- | ------------------------ | ----------------------------------------------------------------------------------------------------------- |
|
|
167
|
+
| `togglApiToken` | `string` | Toggl API token (find it in Toggl → Profile → API Token). Prefer the `TOGGL_API_TOKEN` env var. |
|
|
168
|
+
| `togglWorkspaceId` | `number` | Numeric Toggl workspace ID. Required to push. |
|
|
169
|
+
| `togglProjects` | `Record<string, number>` | Map of ticket-prefix → project ID. Longest matching prefix wins. |
|
|
170
|
+
| `togglDefaultProjectId` | `number` | Project ID for commits that don't match any prefix (or have no ticket). |
|
|
171
|
+
| `togglDefaultDurationMinutes` | `number` | Per-commit duration. Default `30`. In per-ticket mode, an entry's total duration is `count × this`. |
|
|
172
|
+
| `togglDayStartHour` | `number` (0–23) | Hour to start stacking entries at. Default `9` (09:00). |
|
|
173
|
+
| `togglOneEntryPerTicket` | `boolean` | When `true` (default), commits sharing a ticket collapse into one entry. Commits without a ticket stay 1:1. |
|
|
174
|
+
| `togglIgnoreSubjectPattern` | `string` (regex) | Subjects matching this pattern (case-insensitive) are skipped. Default `\bmerge\b`. Set to `""` to disable. |
|
|
175
|
+
|
|
176
|
+
### Auth
|
|
177
|
+
|
|
178
|
+
The API token is resolved in this order: `TOGGL_API_TOKEN` env var > `togglApiToken` in config. The env var path is preferred so you don't have to commit (or remember not to commit) the token.
|
|
179
|
+
|
|
180
|
+
## Managing config
|
|
181
|
+
|
|
182
|
+
`wdid config` provides four subcommands for the **global** config (`~/.config/wdid/config.json` — honors `XDG_CONFIG_HOME`). Repo-level configs are read but not written by these commands; edit them by hand.
|
|
183
|
+
|
|
184
|
+
```sh
|
|
185
|
+
wdid config set togglApiToken tok_… # set a scalar field
|
|
186
|
+
wdid config set togglWorkspaceId 12345 # numbers are parsed
|
|
187
|
+
wdid config set togglOneEntryPerTicket false # booleans take "true"/"false"
|
|
188
|
+
wdid config set togglProjects.ABC- 67890 # set a nested record entry
|
|
189
|
+
wdid config get togglApiToken # secrets are masked
|
|
190
|
+
wdid config get togglApiToken --show-secrets # …unless --show-secrets
|
|
191
|
+
wdid config list # all set fields, aligned, secrets masked
|
|
192
|
+
wdid config list --show-secrets # reveal secrets
|
|
193
|
+
wdid config path # absolute path to the config file
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Notes:
|
|
197
|
+
|
|
198
|
+
- **Validation runs at `set` time** — `wdid config set togglDayStartHour 99` fails immediately with the schema error, the file is never touched.
|
|
199
|
+
- **Secrets are masked** in `list` / `get` output (`tok_…wa9e0d` style) unless `--show-secrets` is set.
|
|
200
|
+
- **`defaultRepos` is not settable from the CLI** (it's an array). Same for any future array-shaped field. Use `vim $(wdid config path)` to edit those.
|
|
201
|
+
- **To remove a key**, edit the file directly — `unset` isn't included in this slice.
|
|
89
202
|
|
|
90
203
|
## Development
|
|
91
204
|
|