logwork-cli 0.0.0-stage → 1.1.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.
Files changed (96) hide show
  1. package/LICENSE +11 -0
  2. package/README.md +330 -2
  3. package/RELEASE.md +89 -0
  4. package/bin/logwork.mjs +104 -0
  5. package/commands/auth.mjs +227 -0
  6. package/commands/commits.mjs +82 -0
  7. package/commands/delete.mjs +69 -0
  8. package/commands/doctor.mjs +24 -0
  9. package/commands/edit.mjs +88 -0
  10. package/commands/history.mjs +62 -0
  11. package/commands/query.mjs +52 -0
  12. package/commands/quick.mjs +163 -0
  13. package/commands/reconcile.mjs +55 -0
  14. package/commands/release.mjs +77 -0
  15. package/commands/reminder.mjs +172 -0
  16. package/commands/setup.mjs +508 -0
  17. package/commands/skill.mjs +91 -0
  18. package/commands/tui.mjs +50 -0
  19. package/commands/update.mjs +161 -0
  20. package/docs/advanced.md +334 -0
  21. package/docs/mcp-setup.md +368 -0
  22. package/docs/operations-guide.md +587 -0
  23. package/docs/recipes.md +259 -0
  24. package/docs/security.md +151 -0
  25. package/examples/mcp/antigravity.mcp_config.json +8 -0
  26. package/examples/mcp/codex.config.toml +5 -0
  27. package/examples/mcp/copilot.mcp.json +9 -0
  28. package/lib/agent-skill.mjs +16 -0
  29. package/lib/api-auth.mjs +1259 -0
  30. package/lib/api.mjs +1422 -0
  31. package/lib/apply-ledger.mjs +227 -0
  32. package/lib/atomic-file.mjs +24 -0
  33. package/lib/auth-diagnostics.mjs +113 -0
  34. package/lib/auth-errors.mjs +22 -0
  35. package/lib/auth-redaction.mjs +78 -0
  36. package/lib/auth-terminal.mjs +97 -0
  37. package/lib/auth.mjs +323 -0
  38. package/lib/batch-parser.mjs +145 -0
  39. package/lib/batch-workflow.mjs +842 -0
  40. package/lib/commit-workflow.mjs +402 -0
  41. package/lib/config.mjs +191 -0
  42. package/lib/credential-store.mjs +130 -0
  43. package/lib/diagnostics.mjs +307 -0
  44. package/lib/entrypoint.mjs +14 -0
  45. package/lib/file-lock.mjs +44 -0
  46. package/lib/http.mjs +125 -0
  47. package/lib/jira-api.mjs +258 -0
  48. package/lib/jira-auth.mjs +203 -0
  49. package/lib/jira-workflow.mjs +523 -0
  50. package/lib/keychain.mjs +105 -0
  51. package/lib/legacy-migration.mjs +66 -0
  52. package/lib/list-navigation.mjs +19 -0
  53. package/lib/logwork-config.mjs +199 -0
  54. package/lib/logwork-f03-enrich.mjs +41 -0
  55. package/lib/macos.mjs +33 -0
  56. package/lib/manual-apply-state.mjs +35 -0
  57. package/lib/manual-commands.mjs +294 -0
  58. package/lib/manual-drafts.mjs +154 -0
  59. package/lib/manual-ink-app.mjs +1654 -0
  60. package/lib/manual-ink-auth.mjs +349 -0
  61. package/lib/manual-ink-ui.mjs +675 -0
  62. package/lib/manual-input.mjs +21 -0
  63. package/lib/manual-logwork-wizard.mjs +310 -0
  64. package/lib/manual-mcp.mjs +187 -0
  65. package/lib/manual-repl.mjs +1037 -0
  66. package/lib/manual-targets.mjs +78 -0
  67. package/lib/mcp-server.mjs +833 -0
  68. package/lib/os-notification.mjs +105 -0
  69. package/lib/package-info.mjs +17 -0
  70. package/lib/paths.mjs +68 -0
  71. package/lib/project-identity.mjs +66 -0
  72. package/lib/project-mapping-workflow.mjs +309 -0
  73. package/lib/project-resolver.mjs +373 -0
  74. package/lib/query-workflow.mjs +553 -0
  75. package/lib/reconciliation-workflow.mjs +446 -0
  76. package/lib/release-doctor.mjs +448 -0
  77. package/lib/reminder-config.mjs +71 -0
  78. package/lib/reminder-scheduler.mjs +301 -0
  79. package/lib/reminder-service.mjs +118 -0
  80. package/lib/reminder-state.mjs +38 -0
  81. package/lib/reminder-workflow.mjs +299 -0
  82. package/lib/ro-delete-args.mjs +38 -0
  83. package/lib/ro-delete-workflow.mjs +115 -0
  84. package/lib/ro-edit-args.mjs +142 -0
  85. package/lib/ro-edit-workflow.mjs +632 -0
  86. package/lib/ro-entry-reader.mjs +56 -0
  87. package/lib/ro-resubmit-workflow.mjs +134 -0
  88. package/lib/terminal-auth-prompts.mjs +120 -0
  89. package/lib/ui.mjs +133 -0
  90. package/lib/update-service.mjs +350 -0
  91. package/lib/util.mjs +66 -0
  92. package/lib/windows-credential-manager.mjs +260 -0
  93. package/lib/worklog-task-resolver.mjs +113 -0
  94. package/package.json +73 -4
  95. package/setup.sh +22 -0
  96. package/skills/logwork/SKILL.md +43 -0
package/LICENSE ADDED
@@ -0,0 +1,11 @@
1
+ Proprietary License
2
+
3
+ Copyright (c) 2026 Truc Tran and contributors.
4
+ All rights reserved.
5
+
6
+ This project is proprietary and is not open source. Use, copying,
7
+ modification, distribution, publication, sublicensing, or sale of this
8
+ software or its documentation is permitted only with prior written permission
9
+ from the copyright holder or under a separate written agreement.
10
+
11
+ No license is granted by implication, estoppel, or otherwise.
package/README.md CHANGED
@@ -1,3 +1,331 @@
1
- # Temporary Holding Version
1
+ # logwork-cli
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [npm version](https://www.npmjs.com/package/logwork-cli)
4
+ [license](LICENSE)
5
+
6
+ Log work to Resource Optimiser (RO) and self-hosted Jira from the terminal, from an MCP server for AI IDEs, or from a terminal UI.
7
+
8
+ One command, `logwork`, covers everything:
9
+
10
+ - `logwork`: the terminal UI.
11
+ - `logwork <command>`: one-shot commands such as `logwork query this-week` or `logwork edit 304032 --task "Bug Fix"`.
12
+ - `logwork mcp`: the MCP server that Cursor, Codex, Google Antigravity, GitHub Copilot / VS Code and Claude Code connect to.
13
+
14
+ Credentials stay local. Resource Optimiser passwords and 2FA codes, and Jira Personal Access Tokens, are entered in the terminal only. They never go into MCP config or AI chat.
15
+
16
+ ## Install
17
+
18
+ Requirements: macOS or Windows 10/11, Node.js 22+, npm.
19
+
20
+ ```bash
21
+ npm install -g logwork-cli
22
+ logwork setup
23
+ ```
24
+
25
+ `logwork setup` does the following:
26
+ - installs the runtime to `~/.logwork-cli` (`%USERPROFILE%\.logwork-cli` on Windows),
27
+ - links the `logwork` command,
28
+ - offers to log in,
29
+ - prints copy-ready MCP configs that use your real local path.
30
+
31
+ ## Upgrading from logwork-helper
32
+
33
+ The package was renamed from `logwork-helper` to `logwork-cli`, and the `logwork-helper` command no longer exists. To upgrade:
34
+
35
+ ```bash
36
+ npm install -g logwork-cli
37
+ logwork setup
38
+ ```
39
+
40
+ Most of the move is automatic:
41
+
42
+ - **Old global package:** `logwork setup` removes the global `logwork-helper` package, so its `logwork` command does not conflict with the new one.
43
+ - **Local state:** on the first run, settings, project mappings, drafts, apply history and the reminder config are copied from `~/.logwork-helper` to `~/.logwork-cli`. The old directory is left in place.
44
+ - **Login sessions:** your RO and Jira sessions are copied from the old Keychain / Credential Manager entry (`logwork-helper`) to the new one (`logwork-cli`), so you do not need to log in again.
45
+ - **Repo mappings:** a repo that has `.logwork-helper.json` keeps using it until a `.logwork.json` exists.
46
+ - **Reminder:** an enabled reminder is re-registered by `logwork setup`, and the old OS schedule is removed.
47
+
48
+ Two things you need to do yourself:
49
+
50
+ - **IDE config:** replace the old `logwork-helper` MCP entry with the new `logwork` entry printed by `logwork setup` or `/mcp`.
51
+ - **MCP tool names:** the tool names changed. See the [old → new tool name table](docs/mcp-setup.md#tool-name-changes-from-logwork-helper).
52
+
53
+ ## Log In
54
+
55
+ ```bash
56
+ logwork login # Resource Optimiser: email, password, 2FA in this terminal
57
+ logwork login jira # Jira Personal Access Token
58
+ logwork login jira --base-url https://jira.example.com
59
+ logwork status # RO and Jira status, never prints tokens
60
+ logwork logout [ro|jira]
61
+ ```
62
+
63
+ Sessions are stored in macOS Keychain or Windows Credential Manager. The default Jira URL is `https://jira-vnv.vinova.sg`.
64
+
65
+ ## Commands
66
+
67
+ ```text
68
+ logwork Open the terminal UI
69
+ logwork query [period] Booked vs logged hours with entry ids (today, yesterday, this-week, last-week, this-month, last-month)
70
+ logwork commits [period] Draft logwork lines from your git commits (--repo, --author)
71
+ logwork quick [-m text] Log one entry for today with guided prompts
72
+ logwork edit <id> ... Change an existing RO entry (replaces it)
73
+ logwork delete <id> Delete a submitted or approved RO entry
74
+ logwork reconcile Compare RO and Jira hours by day (read-only)
75
+ logwork history Local apply history
76
+ logwork login|logout|status [ro|jira]
77
+ logwork skill install Install the AI agent skill (Claude Code, Codex)
78
+ logwork setup Install the runtime and print MCP configs
79
+ logwork mcp Run the MCP stdio server (used by IDE configs)
80
+ logwork reminder ... Weekday logwork reminder
81
+ logwork update ... Check for or install a new version
82
+ logwork doctor Write a sanitized diagnostics report
83
+ ```
84
+
85
+ Add `--help` to any command for its options.
86
+
87
+ ## Log Work From Your Commits
88
+
89
+ Most logwork is the work you committed. logwork turns your commits into draft lines, and the RO booking decides how many hours there are to fill.
90
+
91
+ ```bash
92
+ logwork commits yesterday
93
+ logwork commits this-week --repo ~/code/portal --repo ~/code/api
94
+ ```
95
+
96
+ How the draft is built:
97
+
98
+ - **Which commits:** your own (`git config user.email`, or `--author`) on every local and remote branch. Stashes and merge commits are skipped.
99
+ - **Grouping:** per day, by repo + ticket key + kind of work.
100
+ - **Worklog task:** chosen from the kind of work.
101
+
102
+ | Commit | Worklog task |
103
+ |---|---|
104
+ | `feat` | Feature Development |
105
+ | `fix`, hotfix | Bug Fix |
106
+ | `refactor`, `perf`, review | Code Review & Refactoring |
107
+ | `test` | Testing Activities |
108
+ | `ci`, `build`, release, deploy | Deployment & Release |
109
+ | `docs`, design | Requirements & Design |
110
+ | `chore` | Other Activities |
111
+
112
+ Conventional prefixes are used first, then keywords in the subject.
113
+ - **Hours:** each day's RO remaining time (booked − logged, per project) is split across the groups in 0.5h steps, weighted by commits and lines changed. Days without a booking get 0h. Without RO access, a weekday counts as 8h.
114
+
115
+ Nothing is written. Paste the draft into `/logwork`, or let your AI agent use it.
116
+
117
+ For agents:
118
+ - **MCP tool `draft_from_commits`** returns the same draft as `draftText`.
119
+ - **MCP prompt `log_from_commits`** gives an agent the full procedure:
120
+ 1. find gaps with `get_logwork`;
121
+ 2. draft from commits;
122
+ 3. check task names with `list_tasks`;
123
+ 4. rewrite vague descriptions;
124
+ 5. stay within booked hours;
125
+ 6. get your approval, then `log_work`.
126
+ - **Claude Code / Codex:** `logwork skill install` installs the same procedure as a skill, in `~/.claude/skills/logwork` and `~/.codex/skills/logwork`. For other agents, `logwork skill` prints it so you can paste it into your rules.
127
+
128
+ ## Logwork Line Format
129
+
130
+ Every Resource Optimiser entry has a **worklog task** and a free-text **description**. The worklog task is an RO catalog item such as `Feature Development` or `Code Review & Refactoring`. Write each line as:
131
+
132
+ ```text
133
+ Monday, 01 Jun 2026
134
+ +2 Feature Development | Implement maintenance mode management and status UI (SCB-213)
135
+ +1 Code Review & Refactoring | Review system page PR (SCB-214)
136
+ ```
137
+
138
+ - **Before `|`:** the RO worklog task name, or `#<id>`. MCP clients can list valid names with `list_tasks`.
139
+ - **After `|`:** the description saved on the RO entry. Jira uses it as the worklog comment.
140
+ - **Lines without `|`:** these still work in two cases. If the whole text is a catalog task name, the entry is saved with no description and a warning. If the assistant passes `defaultWorklogTask`, that task is used and the text becomes the description.
141
+
142
+ The default tasks shared by all projects are:
143
+
144
+ | id | Task | type_of_work |
145
+ |---|---|---|
146
+ | 71 | Feature Development | create |
147
+ | 74 | Bug Fix | correct |
148
+ | 182 | Code Review & Refactoring | improve |
149
+ | 79 | Deployment & Release | create |
150
+ | 181 | Requirements & Design | create |
151
+ | 183 | Testing Activities | create |
152
+ | 111 | Other Activities | other |
153
+
154
+ ## API Notes
155
+
156
+ - Read bookings: `GET /member-logtime/timesheet`
157
+ - Read worklog tasks: `GET /logwork/tasks?project_id=<id>` and `GET /logwork/tasks/defaults?project_id=<id>`
158
+ - Write an entry: `POST /logwork/entries`
159
+ - Delete an entry: `DELETE /logwork/entries/:id`
160
+ - Resubmit a rejected entry: `PATCH /logwork/entries/:id/resubmit`
161
+
162
+ ```json
163
+ {
164
+ "worklog_task_id": 71,
165
+ "type_of_work": "create",
166
+ "effort_hours": 2,
167
+ "logdate": "2026-06-01",
168
+ "project_id": 720,
169
+ "description": "Implement maintenance mode management and status UI (SCB-213)"
170
+ }
171
+ ```
172
+
173
+ `project_id` is sent only when the worklog task is a shared default task.
174
+
175
+ ## Set Up MCP
176
+
177
+ `logwork setup` prints the configs. You can also open the terminal UI with `logwork` and type `/mcp` (or `/mcp cursor`, `/mcp antigravity`, `/mcp copilot`, `/mcp claude-code`, `/mcp codex`).
178
+
179
+ Every client runs the same thing, `node ~/.logwork-cli/bin/logwork.mjs mcp`, under the server name `logwork`:
180
+
181
+ ```json
182
+ {
183
+ "mcpServers": {
184
+ "logwork": {
185
+ "command": "node",
186
+ "args": ["/Users/you/.logwork-cli/bin/logwork.mjs", "mcp"]
187
+ }
188
+ }
189
+ }
190
+ ```
191
+
192
+ For Claude Code, run:
193
+
194
+ ```bash
195
+ claude mcp add --transport stdio logwork -- node ~/.logwork-cli/bin/logwork.mjs mcp
196
+ ```
197
+
198
+ Restart or reload the IDE's MCP tools after saving.
199
+
200
+ The server exposes 16 tools and one prompt (`log_from_commits`). It also sends `instructions` covering the approval rules, the line format and the recommended call order. Every write is **two calls to the same tool**:
201
+ 1. Call the tool without `confirm`. It returns a preview with a `batchId` or `previewId` and a summary.
202
+ 2. After the user approves, call the same tool again with only that id and `confirm: true`.
203
+
204
+ See [docs/mcp-setup.md](docs/mcp-setup.md#exposed-tools) for the tool table.
205
+
206
+ Verify from your assistant:
207
+
208
+ ```text
209
+ Check my logwork for this week.
210
+ ```
211
+
212
+ ## Edit Existing RO Logwork
213
+
214
+ Get the entry id from `logwork query` (or `get_logwork` in MCP), then:
215
+
216
+ ```bash
217
+ logwork edit 304032 --hours 0.5
218
+ logwork edit 304032 --desc "Fix date picker timezone (SAP-42)"
219
+ logwork edit 304032 --task "Bug Fix" --desc "Fix date picker timezone (SAP-42)"
220
+ logwork edit 304032 --task "#74" --type correct
221
+ ```
222
+
223
+ Options:
224
+ - `--hours`
225
+ - `--task`: a worklog task from the project catalog, or `#<id>`.
226
+ - `--desc`
227
+ - `--type`: `create`, `correct`, `improve` or `other`. When the task changes and `--type` is omitted, the new task's catalog type is used.
228
+
229
+ The long forms `--task-name` and `--description` also work. Project and date are always preserved.
230
+
231
+ Resource Optimiser has no staff API for editing an entry; the edit endpoint is PM-only. So apply **replaces** the entry:
232
+
233
+ 1. It re-reads the entry and stops if the entry changed after the preview.
234
+ 2. It creates the corrected entry with `POST /logwork/entries`.
235
+ 3. It deletes the original with `DELETE /logwork/entries/:id`.
236
+ 4. It verifies the new entry.
237
+
238
+ If the create fails, the original is untouched. If the delete fails, the new entry is deleted again, so nothing changes.
239
+
240
+ Deleting on RO needs no approval, and a correctly formatted new entry is approved immediately, so the edit takes effect at once. The new entry gets a **new logwork id**.
241
+
242
+ Some entries cannot be edited this way:
243
+ - Only `submitted` or `approved` entries can be edited.
244
+ - Rejected entries are fixed with `resubmit_entry`.
245
+ - Entries on locked days, entries created by Jira, and entries owned by another user are blocked.
246
+
247
+ The CLI previews the diff and asks for confirmation. Use `--yes` for an already reviewed non-interactive command.
248
+
249
+ In the terminal UI: `/edit-logwork 304032 --task Bug Fix --desc Fix date picker timezone (SAP-42)`.
250
+
251
+ In MCP, call `edit_entry` with `logworkId` and the changes, show the summary, then call `edit_entry` with `previewId` and `confirm: true`. The result returns `originalLogworkId` and `newLogworkId`.
252
+
253
+ ## Daily Use
254
+
255
+ Ask your assistant:
256
+
257
+ ```text
258
+ Check whether I have logged anything today.
259
+ ```
260
+
261
+ ```text
262
+ Preview this logwork and ask for my approval before submitting:
263
+ Monday, 01 Jun 2026
264
+ +2 Feature Development | Maintenance mode management and status UI (SCB-213)
265
+ ```
266
+
267
+ ```text
268
+ Set up the SCB ticket mapping to project 2621A-SIT-HTML BUILDER-PRJ.
269
+ ```
270
+
271
+ From the terminal:
272
+
273
+ ```bash
274
+ logwork quick -m "Fix login bug (SCB-12)" # one entry for today
275
+ logwork # terminal UI
276
+ ```
277
+
278
+ In the terminal UI, `/logwork` opens a target picker. `/logwork ro` writes Resource Optimiser entries, `/logwork jira` writes Jira worklogs, and `/logwork both` previews and applies both with separate approvals. Type `/` to see every command, for example:
279
+ - `/query this-week`
280
+ - `/reconcile`
281
+ - `/projects`
282
+ - `/map SCB 5234`
283
+ - `/history`
284
+ - `/diagnostics`
285
+
286
+ ## Reminder
287
+
288
+ ```bash
289
+ logwork reminder enable # 17:00 Monday-Friday, RO and Jira
290
+ logwork reminder enable --time 18:00 --target ro
291
+ logwork reminder test
292
+ logwork reminder status
293
+ logwork reminder disable
294
+ ```
295
+
296
+ For Resource Optimiser, the reminder compares today's logged and booked hours. For Jira, it checks whether you have any worklog today. Complete days stay silent.
297
+
298
+ macOS uses a user `launchd` agent (`sg.vinova.logwork-cli.reminder`) and Windows uses Task Scheduler (`Logwork Reminder`). Neither schedule stores credentials.
299
+
300
+ ## Reconcile RO And Jira
301
+
302
+ ```bash
303
+ logwork reconcile this-week
304
+ logwork reconcile last-month --json
305
+ ```
306
+
307
+ This is read-only. It shows booked, RO and Jira hours by day and flags mismatches. A correction suggestion is included only when an RO entry contains exactly one Jira issue key. Applying a suggestion still goes through the normal preview and approval flow. MCP clients use the `reconcile` tool.
308
+
309
+ ## Update
310
+
311
+ ```bash
312
+ logwork update check
313
+ logwork update install
314
+ ```
315
+
316
+ The terminal UI shows a short notice when a newer release is available. Checks are cached for 24 hours, and network errors never block logwork.
317
+
318
+ Updating keeps OS credentials, project mappings, drafts and apply history. Reconnect MCP clients after an update.
319
+
320
+ ## More Docs
321
+
322
+ - [Operations guide](docs/operations-guide.md): CLI/MCP feature map, RO/Jira/Both processing, mapping, reconciliation, history, reminders, updates and OS validation.
323
+ - [MCP setup](docs/mcp-setup.md): client configs, the tool table, the old → new tool names, and common workflows.
324
+ - [Security and auth](docs/security.md): Keycloak flow, Jira PAT flow, OS credential storage, stored files and the safety model.
325
+ - [Advanced usage](docs/advanced.md): environment overrides, terminal UI details, troubleshooting and release checks.
326
+ - [Quick recipes](docs/recipes.md): copy-ready workflows.
327
+ - [Release checklist](RELEASE.md).
328
+
329
+ ## License
330
+
331
+ This project is proprietary and not open source. See [LICENSE](LICENSE).
package/RELEASE.md ADDED
@@ -0,0 +1,89 @@
1
+ # Release Checklist
2
+
3
+ Use this checklist before publishing or tagging a production release.
4
+
5
+ The complete end-user update and maintainer publish flows are documented in the [integrated operations guide](docs/operations-guide.md).
6
+
7
+ ## Version And Publish Sequence
8
+
9
+ Publishing is automated. Pushing a version bump to `main` is the release:
10
+
11
+ ```bash
12
+ # 1. Add "## [<version>] - <date>" with a ### Summary to CHANGELOG.md
13
+ npm version <version> --no-git-tag-version
14
+ npm run release:check
15
+ git add -A
16
+ git commit -m "release v<version>"
17
+ git push origin main
18
+ ```
19
+
20
+ After CI passes on `main`, `.github/workflows/release.yml`:
21
+
22
+ 1. reads the version from `package.json`;
23
+ 2. publishes `logwork-cli@<version>` to npm with provenance, using the `NPM_TOKEN` repository secret (skipped if already published);
24
+ 3. creates tag `v<version>` and a GitHub Release whose description is the `CHANGELOG.md` section (skipped if the tag exists).
25
+
26
+ Check the result:
27
+
28
+ ```bash
29
+ gh run list --workflow Release --limit 3
30
+ npm view logwork-cli version
31
+ gh release view v<version>
32
+ ```
33
+
34
+ To retry a failed release, re-run the Release workflow (or `gh workflow run Release`). Use `minor` or `major` instead of `patch` when required by SemVer. Never reuse an already published version.
35
+
36
+ ### npm token
37
+
38
+ The workflow uses the `NPM_TOKEN` repository secret (an npm automation or granular token with publish rights to `logwork-cli`). Set or rotate it with `gh secret set NPM_TOKEN --repo malcohelper/logwork-cli` and paste the token at the prompt. Never put the token in files, commits or command arguments. Preferred long term: configure npm Trusted Publishing for this repo and workflow on npmjs.com, then delete the secret; `npm publish --provenance` in the workflow already runs with `id-token: write`.
39
+
40
+ ## Required Gates
41
+
42
+ Run the local release gate:
43
+
44
+ ```bash
45
+ npm run release:check
46
+ ```
47
+
48
+ Before publishing, run the release preflight doctor:
49
+
50
+ ```bash
51
+ logwork release doctor --full
52
+ ```
53
+
54
+ This checks version consistency, git cleanliness, npm auth, npm latest version, GitHub auth, tag/release state, local tarball artifacts, tests, audit, pack dry-run, and diff whitespace.
55
+
56
+ The gate must pass all of the following:
57
+
58
+ - `npm test`
59
+ - `npm audit --omit=dev --audit-level=moderate`
60
+ - `npm pack --dry-run`
61
+ - `git diff --check`
62
+
63
+ ## Manual Verification
64
+
65
+ - Install from the packed tarball in a temporary directory.
66
+ - Run `logwork setup --no-login`.
67
+ - Confirm the printed MCP config uses server name `logwork` and `node ~/.logwork-cli/bin/logwork.mjs mcp`.
68
+ - Run `logwork --help` and `logwork --version`.
69
+ - Run `logwork update check --force` against the published npm version.
70
+ - Run `logwork mcp` through an MCP client smoke test and confirm it lists the 16 tools (`get_logwork`, `draft_from_commits`, `list_projects`, `list_tasks`, `log_work`, `edit_entry`, `resubmit_entry`, `delete_entry`, `log_jira_work`, `get_jira_issue`, `reconcile`, `get_history`, `map_project`, `login`, `reminder`, `update`).
71
+ - Confirm the `update` tool requires `confirm: true` for `action: "install"`, and `reconcile` takes preset periods only with no credential or confirmation fields.
72
+ - Run `logwork reconcile this-week` and confirm it reports RO/Jira daily totals without writing either system.
73
+ - On a machine with an older `logwork-helper` install, confirm the first run copies state to `~/.logwork-cli` and `logwork status` shows the existing session without a new login.
74
+ - Confirm the Windows CI job passes the dedicated `Verify Windows Credential Manager integration` step.
75
+ - Run `logwork reminder test`, confirm a native notification appears, then verify `logwork reminder status` and clean up with `logwork reminder disable`.
76
+ - Run `logwork status` and confirm no token is printed.
77
+
78
+ ## Safety Checks
79
+
80
+ - Do not include Resource Optimiser tokens, `.env` files, diagnostics reports, or machine-specific MCP configs in the package.
81
+ - Confirm `logwork --version` and the MCP server version match `package.json`.
82
+ - Confirm `README.md` and onboarding output describe the same primary setup flow.
83
+ - Confirm no untracked release artifacts are included except intentional documentation.
84
+
85
+ ## Rollback
86
+
87
+ - Keep the previous npm package version available.
88
+ - If a release introduces auth, MCP, or apply-path regressions, roll back by instructing users to install the previous known-good npm version.
89
+ - Do not publish a replacement with the same version; publish a new patch version after the fix is verified.
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { isMainModule } from '../lib/entrypoint.mjs';
4
+ import { migrateLegacyHome } from '../lib/legacy-migration.mjs';
5
+ import { readPackageVersion } from '../lib/package-info.mjs';
6
+
7
+ // One entry point for every surface:
8
+ // logwork -> terminal UI
9
+ // logwork <command> ... -> CLI command (loaded on demand, run in-process)
10
+ // logwork mcp -> MCP stdio server for IDEs and agent CLIs
11
+ export const COMMANDS = [
12
+ { name: 'query', usage: 'query [today|yesterday|this-week|last-week|this-month|last-month] [--json]', summary: 'Show booked vs logged hours with entry ids', load: () => import('../commands/query.mjs'), fn: 'run' },
13
+ { name: 'commits', usage: 'commits [period] [--repo path]... [--author email]', summary: 'Draft logwork lines from your git commits', load: () => import('../commands/commits.mjs'), fn: 'run' },
14
+ { name: 'quick', usage: 'quick [-m "what you did"]', summary: 'Log one entry for today with guided prompts', load: () => import('../commands/quick.mjs'), fn: 'run' },
15
+ { name: 'edit', usage: 'edit <id> [--hours h] [--task name|#id] [--desc text] [--type type]', summary: 'Change an existing RO entry (replaces it)', load: () => import('../commands/edit.mjs'), fn: 'runRoEditCommand' },
16
+ { name: 'delete', usage: 'delete <id>', summary: 'Delete a submitted or approved RO entry', load: () => import('../commands/delete.mjs'), fn: 'runRoDeleteCommand' },
17
+ { name: 'reconcile', usage: 'reconcile [period] [--json]', summary: 'Compare RO and Jira hours by day', load: () => import('../commands/reconcile.mjs'), fn: 'runReconcileCommand' },
18
+ { name: 'history', usage: 'history [--target ro|jira|both] [--limit n] [--json]', summary: 'Show the local apply history', load: () => import('../commands/history.mjs'), fn: 'runHistoryCommand' },
19
+ { name: 'login', usage: 'login [ro|jira] [--base-url url]', summary: 'Log in to Resource Optimiser (default) or Jira', load: () => import('../commands/auth.mjs'), fn: 'runLogin' },
20
+ { name: 'logout', usage: 'logout [ro|jira]', summary: 'Remove the stored RO (default) or Jira session', load: () => import('../commands/auth.mjs'), fn: 'runLogout' },
21
+ { name: 'status', usage: 'status', summary: 'Show RO and Jira login status', load: () => import('../commands/auth.mjs'), fn: 'runStatus' },
22
+ { name: 'skill', usage: 'skill [print|install] [--target claude|codex|all]', summary: 'Print or install the AI agent skill for logging from commits', load: () => import('../commands/skill.mjs'), fn: 'run' },
23
+ { name: 'setup', usage: 'setup [--login|--no-login]', summary: 'Install the runtime and print MCP configs', load: () => import('../commands/setup.mjs'), fn: 'run' },
24
+ { name: 'mcp', usage: 'mcp', summary: 'Run the MCP stdio server (used by IDE configs)', load: () => import('../lib/mcp-server.mjs'), fn: 'startMcpServer' },
25
+ { name: 'reminder', usage: 'reminder enable|disable|status|test', summary: 'Manage the weekday logwork reminder', load: () => import('../commands/reminder.mjs'), fn: 'runReminderCli' },
26
+ { name: 'update', usage: 'update [check|install]', summary: 'Check for or install a new version', load: () => import('../commands/update.mjs'), fn: 'runUpdateCli' },
27
+ { name: 'doctor', usage: 'doctor', summary: 'Write a sanitized diagnostics report', load: () => import('../commands/doctor.mjs'), fn: 'run' },
28
+ { name: 'release', usage: 'release doctor [--full]', summary: 'Maintainers: check release readiness', load: () => import('../commands/release.mjs'), fn: 'run' }
29
+ ];
30
+
31
+ export async function run(argv = process.argv.slice(2)) {
32
+ const [first, ...rest] = argv;
33
+
34
+ if (first === '--version' || first === '-v') {
35
+ console.log(readPackageVersion());
36
+ return 0;
37
+ }
38
+ if (first === '--help' || first === '-h' || first === 'help') {
39
+ console.log(formatHelp());
40
+ return 0;
41
+ }
42
+
43
+ if (first !== 'mcp') {
44
+ reportMigration(migrateLegacyHome());
45
+ }
46
+
47
+ if (!first || first.startsWith('-')) {
48
+ const tui = await import('../commands/tui.mjs');
49
+ return tui.run(argv);
50
+ }
51
+
52
+ const command = COMMANDS.find((item) => item.name === first);
53
+ if (!command) {
54
+ console.error(`Unknown command: ${first}\n`);
55
+ console.error(formatHelp());
56
+ return 1;
57
+ }
58
+
59
+ if (command.name === 'mcp') {
60
+ migrateLegacyHome();
61
+ }
62
+ const module = await command.load();
63
+ const result = await module[command.fn](rest);
64
+ return typeof result === 'number' ? result : undefined;
65
+ }
66
+
67
+ export function formatHelp() {
68
+ const width = Math.max(...COMMANDS.map((command) => command.name.length));
69
+ return `Usage:
70
+ logwork Open the terminal UI
71
+ logwork <command> Run one command (add --help for its options)
72
+
73
+ Commands:
74
+ ${COMMANDS.map((command) => ` ${command.name.padEnd(width)} ${command.summary}`).join('\n')}
75
+
76
+ Examples:
77
+ logwork setup
78
+ logwork login
79
+ logwork query this-week
80
+ logwork commits yesterday --repo ~/code/app
81
+ logwork quick -m "Fix login bug (SCB-12)"
82
+ logwork edit 304032 --task "Bug Fix" --desc "Fix date picker timezone (SAP-42)"
83
+
84
+ Options:
85
+ -h, --help Show help
86
+ -v, --version Show version`;
87
+ }
88
+
89
+ function reportMigration(result) {
90
+ if (result?.migrated) {
91
+ console.error(`Moved local settings from ${result.from} to ${result.to}.`);
92
+ }
93
+ }
94
+
95
+ if (isMainModule(import.meta.url)) {
96
+ run().then((code) => {
97
+ if (typeof code === 'number') {
98
+ process.exitCode = code;
99
+ }
100
+ }).catch((error) => {
101
+ console.error(error.message);
102
+ process.exitCode = 1;
103
+ });
104
+ }