logwork-cli 0.0.0-stage → 1.0.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 (91) hide show
  1. package/LICENSE +11 -0
  2. package/README.md +287 -2
  3. package/RELEASE.md +89 -0
  4. package/bin/logwork.mjs +101 -0
  5. package/commands/auth.mjs +227 -0
  6. package/commands/delete.mjs +69 -0
  7. package/commands/doctor.mjs +24 -0
  8. package/commands/edit.mjs +88 -0
  9. package/commands/history.mjs +62 -0
  10. package/commands/query.mjs +52 -0
  11. package/commands/quick.mjs +163 -0
  12. package/commands/reconcile.mjs +55 -0
  13. package/commands/release.mjs +77 -0
  14. package/commands/reminder.mjs +172 -0
  15. package/commands/setup.mjs +504 -0
  16. package/commands/tui.mjs +50 -0
  17. package/commands/update.mjs +161 -0
  18. package/docs/advanced.md +334 -0
  19. package/docs/mcp-setup.md +347 -0
  20. package/docs/operations-guide.md +587 -0
  21. package/docs/recipes.md +259 -0
  22. package/docs/security.md +151 -0
  23. package/examples/mcp/antigravity.mcp_config.json +8 -0
  24. package/examples/mcp/codex.config.toml +5 -0
  25. package/examples/mcp/copilot.mcp.json +9 -0
  26. package/lib/api-auth.mjs +1259 -0
  27. package/lib/api.mjs +1422 -0
  28. package/lib/apply-ledger.mjs +227 -0
  29. package/lib/atomic-file.mjs +24 -0
  30. package/lib/auth-diagnostics.mjs +113 -0
  31. package/lib/auth-errors.mjs +22 -0
  32. package/lib/auth-redaction.mjs +78 -0
  33. package/lib/auth-terminal.mjs +97 -0
  34. package/lib/auth.mjs +323 -0
  35. package/lib/batch-parser.mjs +145 -0
  36. package/lib/batch-workflow.mjs +842 -0
  37. package/lib/config.mjs +191 -0
  38. package/lib/credential-store.mjs +130 -0
  39. package/lib/diagnostics.mjs +307 -0
  40. package/lib/entrypoint.mjs +14 -0
  41. package/lib/file-lock.mjs +44 -0
  42. package/lib/http.mjs +125 -0
  43. package/lib/jira-api.mjs +258 -0
  44. package/lib/jira-auth.mjs +203 -0
  45. package/lib/jira-workflow.mjs +523 -0
  46. package/lib/keychain.mjs +105 -0
  47. package/lib/legacy-migration.mjs +66 -0
  48. package/lib/list-navigation.mjs +19 -0
  49. package/lib/logwork-config.mjs +199 -0
  50. package/lib/logwork-f03-enrich.mjs +41 -0
  51. package/lib/macos.mjs +33 -0
  52. package/lib/manual-apply-state.mjs +35 -0
  53. package/lib/manual-commands.mjs +294 -0
  54. package/lib/manual-drafts.mjs +154 -0
  55. package/lib/manual-ink-app.mjs +1654 -0
  56. package/lib/manual-ink-auth.mjs +349 -0
  57. package/lib/manual-ink-ui.mjs +675 -0
  58. package/lib/manual-input.mjs +21 -0
  59. package/lib/manual-logwork-wizard.mjs +310 -0
  60. package/lib/manual-mcp.mjs +187 -0
  61. package/lib/manual-repl.mjs +1037 -0
  62. package/lib/manual-targets.mjs +78 -0
  63. package/lib/mcp-server.mjs +793 -0
  64. package/lib/os-notification.mjs +105 -0
  65. package/lib/package-info.mjs +17 -0
  66. package/lib/paths.mjs +68 -0
  67. package/lib/project-identity.mjs +66 -0
  68. package/lib/project-mapping-workflow.mjs +309 -0
  69. package/lib/project-resolver.mjs +373 -0
  70. package/lib/query-workflow.mjs +553 -0
  71. package/lib/reconciliation-workflow.mjs +446 -0
  72. package/lib/release-doctor.mjs +448 -0
  73. package/lib/reminder-config.mjs +71 -0
  74. package/lib/reminder-scheduler.mjs +301 -0
  75. package/lib/reminder-service.mjs +118 -0
  76. package/lib/reminder-state.mjs +38 -0
  77. package/lib/reminder-workflow.mjs +299 -0
  78. package/lib/ro-delete-args.mjs +38 -0
  79. package/lib/ro-delete-workflow.mjs +115 -0
  80. package/lib/ro-edit-args.mjs +142 -0
  81. package/lib/ro-edit-workflow.mjs +632 -0
  82. package/lib/ro-entry-reader.mjs +56 -0
  83. package/lib/ro-resubmit-workflow.mjs +134 -0
  84. package/lib/terminal-auth-prompts.mjs +120 -0
  85. package/lib/ui.mjs +133 -0
  86. package/lib/update-service.mjs +350 -0
  87. package/lib/util.mjs +66 -0
  88. package/lib/windows-credential-manager.mjs +260 -0
  89. package/lib/worklog-task-resolver.mjs +113 -0
  90. package/package.json +72 -4
  91. package/setup.sh +22 -0
@@ -0,0 +1,334 @@
1
+ # Advanced Usage
2
+
3
+ This file keeps technical details out of the main README. Most users only need `npm install -g logwork-cli`, `logwork setup`, `logwork login`, and `/mcp`.
4
+
5
+ For one consolidated reference covering all newly integrated CLI and MCP workflows, see the [integrated operations guide](operations-guide.md).
6
+
7
+ ## Environment Configuration
8
+
9
+ Defaults target the current Resource Optimiser / Vinova profile. For non-default deployments, configure the runtime with environment variables instead of editing source:
10
+
11
+ ```bash
12
+ LOGWORK_PROFILE=vinova
13
+ LOGWORK_API_BASE=https://api.resourceoptimiser.com/api/v1
14
+ LOGWORK_LOGIN_URL=https://app.resourceoptimiser.com/vinova
15
+ LOGWORK_JIRA_BASE_URL=https://jira-vnv.vinova.sg
16
+ LOGWORK_JIRA_STARTED_TIME=09:00
17
+ LOGWORK_TIMEZONE=Asia/Ho_Chi_Minh
18
+ LOGWORK_KEYCLOAK_AUTH_URL=https://keycloak.vinova.sg/auth/realms/resource/protocol/openid-connect/auth
19
+ LOGWORK_KEYCLOAK_TOKEN_URL=https://keycloak.vinova.sg/auth/realms/resource/protocol/openid-connect/token
20
+ LOGWORK_KEYCLOAK_REDIRECT_URI=https://app.resourceoptimiser.com/vinova/check-login
21
+ ```
22
+
23
+ In Windows PowerShell, set the same values with `$env:NAME = "value"` before running `logwork`.
24
+
25
+ Supported overrides:
26
+
27
+ ```text
28
+ LOGWORK_PROFILE (LOGWORK_HELPER_PROFILE still accepted)
29
+ LOGWORK_HOME (local state directory; LOGWORK_HELPER_HOME still accepted)
30
+ LOGWORK_DRY_RUN=1 (RO writes return the request body instead of calling the API)
31
+ LOGWORK_API_BASE
32
+ LOGWORK_LOGIN_URL
33
+ LOGWORK_JIRA_BASE_URL
34
+ LOGWORK_JIRA_STARTED_TIME
35
+ LOGWORK_TIMEZONE
36
+ LOGWORK_TOKEN_KEY
37
+ LOGWORK_ALLOWED_SAFARI_HOSTS
38
+ LOGWORK_KEYCLOAK_AUTH_URL
39
+ LOGWORK_KEYCLOAK_TOKEN_URL
40
+ LOGWORK_KEYCLOAK_CLIENT_ID
41
+ LOGWORK_KEYCLOAK_REDIRECT_URI
42
+ LOGWORK_KEYCLOAK_SCOPE
43
+ LOGWORK_KEYCLOAK_RESPONSE_MODE
44
+ LOGWORK_KEYCLOAK_RESPONSE_TYPE
45
+ LOGWORK_HTTP_TIMEOUT_MS
46
+ LOGWORK_HTTP_READ_RETRIES
47
+ LOGWORK_HTTP_RETRY_DELAY_MS
48
+ LOGWORK_DAY_LOG_CONCURRENCY
49
+ ```
50
+
51
+ URL and numeric overrides are validated on startup. Invalid values fail fast so the helper does not log work against an unintended endpoint.
52
+
53
+ ## Install Alternatives
54
+
55
+ The recommended install path is:
56
+
57
+ ```bash
58
+ npm install -g logwork-cli
59
+ logwork setup --no-login
60
+ ```
61
+
62
+ One-off setup without a prior global install:
63
+
64
+ ```bash
65
+ npx -y logwork-cli setup --no-login
66
+ ```
67
+
68
+ Yarn global install:
69
+
70
+ ```bash
71
+ yarn global add logwork-cli
72
+ logwork setup --no-login
73
+ ```
74
+
75
+ To install and start auth immediately:
76
+
77
+ ```bash
78
+ logwork setup --login
79
+ ```
80
+
81
+ Use `--no-login` when installing in scripts or CI.
82
+
83
+ `logwork setup` copies the package into `~/.logwork-cli`, runs `npm ci --omit=dev` there, removes a globally installed `logwork-helper` package (its `logwork` bin would block linking), runs `npm link`, re-registers an enabled reminder, and prints MCP configs.
84
+
85
+ ## Update
86
+
87
+ ```bash
88
+ logwork update check # uses a 24-hour cache
89
+ logwork update check --force # query npm now
90
+ logwork update install # interactive confirmation
91
+ logwork update install --version 0.3.1 --yes
92
+ ```
93
+
94
+ The installer accepts only the version currently published under npm's `latest` tag. It runs `npm exec --package=logwork-cli@<version> -- logwork setup --no-login` with a fixed argument list. Then it verifies the copied `package.json` version in `~/.logwork-cli`.
95
+
96
+ Project mappings, drafts, apply history, update cache, and OS credential-store records are preserved.
97
+
98
+ The `logwork` terminal UI performs a cached check at startup and shows a one-line notice when an update exists. Registry failures are ignored in this startup path, so offline use still works.
99
+
100
+ MCP exposes the same update through the `update` tool:
101
+ - `action: "check"` is read-only.
102
+ - `action: "install"` requires `confirm: true`. It does not accept a registry or an arbitrary command, and it re-checks npm immediately before installing.
103
+
104
+ Reconnect or reload the IDE MCP server after updating.
105
+
106
+ Manual recovery path:
107
+
108
+ ```bash
109
+ npm install -g logwork-cli@latest
110
+ logwork setup --no-login
111
+ ```
112
+
113
+ ## Native Logwork Reminder
114
+
115
+ Enable the default weekday reminder:
116
+
117
+ ```bash
118
+ logwork reminder enable
119
+ ```
120
+
121
+ Defaults:
122
+
123
+ - Local OS time `17:00`.
124
+ - Monday-Friday.
125
+ - Target `both`.
126
+ - At most one notification per day.
127
+ - No notification when all enabled checks are complete.
128
+
129
+ Customize the time or target:
130
+
131
+ ```bash
132
+ logwork reminder enable --time 18:00 --target ro
133
+ logwork reminder enable --time 17:45 --target jira
134
+ ```
135
+
136
+ Inspect, test, or remove the reminder:
137
+
138
+ ```bash
139
+ logwork reminder status
140
+ logwork reminder test
141
+ logwork reminder disable
142
+ ```
143
+
144
+ How the reminder is scheduled:
145
+ - **macOS:** it writes `~/Library/LaunchAgents/sg.vinova.logwork-cli.reminder.plist` and loads it with `launchctl`.
146
+ - **Windows:** it creates the interactive user task `Logwork Reminder` with `schtasks.exe`.
147
+
148
+ Both schedulers run `node ~/.logwork-cli/bin/logwork.mjs reminder run --home ~/.logwork-cli`. That command reads credentials from macOS Keychain or Windows Credential Manager when it runs. Enabling or disabling the reminder also removes the old `logwork-helper` schedule (`sg.vinova.logwork-helper.reminder` / `Logwork Helper Reminder`) if one is still present.
149
+
150
+ Resource Optimiser is incomplete when today's logged hours are lower than booked hours. A day with no RO bookings and no RO logs is treated as not expected. Jira is incomplete when JQL finds no issue with a worklog by `currentUser()` on today's date. Auth or check failures produce an actionable notification without including the underlying API response.
151
+
152
+ The `test` command sends a sample notification immediately and does not query or write RO/Jira. On macOS, allow notifications when prompted. On Windows, ensure app notifications are enabled for PowerShell because the lightweight WinRT toast is delivered through the built-in PowerShell host.
153
+
154
+ ## Reconcile Resource Optimiser And Jira
155
+
156
+ Use the same preset periods as `/query`:
157
+
158
+ ```bash
159
+ logwork reconcile today
160
+ logwork reconcile this-week
161
+ logwork reconcile last-week --json
162
+ ```
163
+
164
+ The command queries RO task details and Jira worklogs authored by the authenticated Jira user. Jira issues are discovered with an exclusive date-range JQL query, then each issue's worklogs are filtered again by author and started date. The result includes booked, RO, and Jira hours by day; total and issue-level differences; missing task-detail diagnostics; and high-confidence correction suggestions.
165
+
166
+ A suggestion is high confidence only when an RO entry contains exactly one issue key such as `SCB-213`. Jira-to-RO suggestions still require project resolution. Reconciliation is read-only and never calls either apply workflow.
167
+
168
+ Inside the terminal UI, `/reconcile` opens a period picker. Direct commands are also available:
169
+
170
+ ```text
171
+ /reconcile today
172
+ /reconcile yesterday
173
+ /reconcile this-week
174
+ /reconcile last-week
175
+ /reconcile this-month
176
+ /reconcile last-month
177
+ ```
178
+
179
+ MCP exposes the same workflow as `reconcile`. To correct a mismatch, preview it with `log_work`, `edit_entry` or `log_jira_work`, inspect the preview, and apply each target separately after approval.
180
+
181
+ ## Terminal UI
182
+
183
+ If you want to log work directly from Terminal without an MCP client, use the React + Ink manual session:
184
+
185
+ ```bash
186
+ logwork
187
+ ```
188
+
189
+ Prompt preview:
190
+
191
+ ```text
192
+ Logwork
193
+ cwd: /path/to/repo
194
+
195
+ logwork > /
196
+ > /help Show this help
197
+ /auth Authenticate Resource Optimiser or show Jira login command
198
+ /status Show Resource Optimiser and Jira auth status
199
+ /diagnostics Write a sanitized report
200
+ /query Query logwork by preset period
201
+ /logwork Create Resource Optimiser, Jira, or combined logwork
202
+ /mcp Show copy-ready MCP setup
203
+ ```
204
+
205
+ Useful commands inside the session:
206
+
207
+ ```text
208
+ /query today
209
+ /query yesterday
210
+ /query this-week
211
+ /query last-week
212
+ /query this-month
213
+ /query last-month
214
+ /reconcile
215
+ /reconcile this-week
216
+ /logwork
217
+ /logwork ro
218
+ /logwork jira
219
+ /logwork both
220
+ /edit-logwork 304032 --task Bug Fix --desc Fix date picker (SAP-42)
221
+ /mcp
222
+ /projects
223
+ /projects 5234
224
+ /map SCB 5234
225
+ /history
226
+ /diagnostics
227
+ ```
228
+
229
+ `/logwork` opens a target picker for Resource Optimiser, Jira, or Both. `/logwork ro` starts the Resource Optimiser wizard: pick a day in the current week, pick a Resource Optimiser project, then enter one task per line as `+<hours> <worklog task> | <description>`. The worklog task must be a Resource Optimiser catalog task for that project; the description is stored on the RO entry:
230
+
231
+ ```text
232
+ +2 Feature Development | check ui/ux
233
+ +1.5 Feature Development | polish reset password state
234
+ ```
235
+
236
+ `/logwork jira` starts the Jira worklog wizard: pick a day, then enter tasks with exactly one Jira issue key:
237
+
238
+ ```text
239
+ +2 Feature Development | check ui/ux (SCB-213)
240
+ +1.5 Feature Development | polish reset password state (SCB-214)
241
+ ```
242
+
243
+ `/logwork both` uses one date/task draft, builds separate Resource Optimiser and Jira previews, then asks for separate approvals when applying.
244
+
245
+ Inside `/logwork`, press Enter on an empty input to apply the ready preview. Use `/remove` to open a multi-select task remover, `/edit` to replace a task, `/save` to persist a local draft, or `Esc` to cancel with confirmation.
246
+
247
+ While the `task >` prompt is active, type `/` to see task-only actions:
248
+
249
+ ```text
250
+ /save Save this draft locally
251
+ /drafts Resume or delete saved drafts
252
+ /diagnostics Write a sanitized support report
253
+ /remove Select tasks to delete
254
+ /edit Select one task and replace it
255
+ /clear Clear current task list
256
+ /back Return to project picker
257
+ /cancel Discard this logwork session
258
+ ```
259
+
260
+ Resource Optimiser drafts saved with `/save` are stored locally at `~/.logwork-cli/manual-drafts.json` on macOS or `%USERPROFILE%\.logwork-cli\manual-drafts.json` on Windows. Drafts never contain tokens, passwords, or OTPs.
261
+
262
+ Successful, partial, failed, and blocked apply outcomes are recorded in `~/.logwork-cli/apply-ledger.json`. The ledger contains only sanitized batch, entry, project, issue, status, and timestamp metadata. Read it with:
263
+
264
+ ```bash
265
+ logwork history
266
+ logwork history --target jira --limit 10
267
+ logwork history --target both
268
+ ```
269
+
270
+ Inside `logwork`, use `/history`, `/history ro`, `/history jira`, or `/history both`. The `both` filter means records created while using the combined Both flow.
271
+
272
+ ## Troubleshooting
273
+
274
+ - **IDE does not show tools:** restart or reload the MCP client. Check that the config runs `node ~/.logwork-cli/bin/logwork.mjs mcp` (on Windows, `%USERPROFILE%\.logwork-cli\bin\logwork.mjs`) and that the server name is `logwork`.
275
+ - **Tools show old names such as `preview_logwork_batch`:** the IDE is still connected to the old `logwork-helper` entry. Replace that entry with the config printed by `logwork setup`; the [tool name table](mcp-setup.md#tool-name-changes-from-logwork-helper) lists the renames.
276
+ - **`logwork: command not found` after `logwork setup`:** open a new terminal first. If it still fails, run `npm install -g logwork-cli`, or make sure your npm global bin directory is on `PATH`.
277
+ - **`npm link` fails with `EEXIST` on `logwork`:** an old global `logwork-helper` package still owns the bin. Run `npm rm -g logwork-helper`, then `logwork setup` again.
278
+ - **Not authenticated to Resource Optimiser:** run `logwork login`, or ask the assistant to call `login`. Enter secrets only in the terminal.
279
+ - **Not authenticated to Jira:** run `logwork login jira`, or ask the assistant to call `login` with `target: "jira"`. Paste the Jira PAT only in the terminal.
280
+ - **Auth error after 2FA:** retry `logwork login`. If it still fails, run `logwork doctor` and send only the generated sanitized report.
281
+ - **Jira worklog preview is blocked:** every Jira entry must include exactly one issue key, such as `SCB-213`. Duplicate Jira worklogs block the apply and cannot be overridden.
282
+ - **Apply says no cached preview:** previews expire after 1 hour and are lost when the MCP server restarts. Preview again.
283
+ - **No project matched:** ask the assistant to call `list_projects`, choose the correct project, then call `map_project`.
284
+ - **Never paste Bearer tokens, cookies, passwords, OTPs, or raw curl auth logs:** auth is handled locally, and the MCP config should only contain `command` and `args`.
285
+
286
+ ## Dry Run
287
+
288
+ `LOGWORK_DRY_RUN=1` makes Resource Optimiser writes return the request body instead of calling the API. Reads still hit the API.
289
+
290
+ ```bash
291
+ LOGWORK_DRY_RUN=1 logwork quick -m "Dry run task"
292
+ LOGWORK_DRY_RUN=1 logwork edit 304032 --desc "Dry run" --yes
293
+ ```
294
+
295
+ In Windows PowerShell:
296
+
297
+ ```powershell
298
+ $env:LOGWORK_DRY_RUN = "1"; logwork quick -m "Dry run task"
299
+ ```
300
+
301
+ ## Release Checks
302
+
303
+ Before publishing or tagging a release, run:
304
+
305
+ ```bash
306
+ logwork release doctor --full
307
+ npm run release:check
308
+ ```
309
+
310
+ The release doctor checks version consistency, git state, npm/GitHub auth, npm latest, tag/release state, local tarball artifacts, tests, audit, package dry run, and whitespace checks. See [RELEASE.md](../RELEASE.md) for the full checklist and manual verification steps.
311
+
312
+ ## GitHub About Metadata
313
+
314
+ Suggested repository description:
315
+
316
+ ```text
317
+ Log work to Resource Optimiser and Jira from the terminal, an MCP server for AI IDEs, and a terminal UI.
318
+ ```
319
+
320
+ Suggested topics:
321
+
322
+ ```text
323
+ resource-optimiser
324
+ logwork
325
+ mcp-server
326
+ nodejs
327
+ macos
328
+ windows
329
+ keycloak
330
+ codex
331
+ cursor
332
+ vscode
333
+ claude-code
334
+ ```
@@ -0,0 +1,347 @@
1
+ # MCP Setup
2
+
3
+ `logwork setup` prints copy-ready configs that use your real path. You can also open the terminal UI with `logwork` and type `/mcp`, or `/mcp <client>` for a single client.
4
+
5
+ For the full RO/Jira/Both processing model, mapping, reconciliation, history, reminders and updates, see the [operations guide](operations-guide.md).
6
+
7
+ Every client runs `node <home>/.logwork-cli/bin/logwork.mjs mcp` under the server name `logwork`.
8
+
9
+ The config uses an absolute `node` entry path instead of the `logwork` command. GUI IDEs often start without the npm global bin directory on `PATH`, so the bare command may not be found.
10
+
11
+ The examples use `/Users/<user>` as a macOS placeholder. On Windows, use the path printed by `logwork setup` or `/mcp`, usually `C:\\Users\\<user>\\.logwork-cli\\bin\\logwork.mjs` inside JSON or TOML strings.
12
+
13
+ ## Cursor / Google Antigravity
14
+
15
+ Cursor MCP settings, or `~/.gemini/antigravity/mcp_config.json`:
16
+
17
+ ```json
18
+ {
19
+ "mcpServers": {
20
+ "logwork": {
21
+ "command": "node",
22
+ "args": ["/Users/<user>/.logwork-cli/bin/logwork.mjs", "mcp"]
23
+ }
24
+ }
25
+ }
26
+ ```
27
+
28
+ ## Codex
29
+
30
+ `~/.codex/config.toml`, or project `.codex/config.toml`:
31
+
32
+ ```toml
33
+ [mcp_servers.logwork]
34
+ command = "node"
35
+ args = ["/Users/<user>/.logwork-cli/bin/logwork.mjs", "mcp"]
36
+ startup_timeout_sec = 20
37
+ tool_timeout_sec = 120
38
+ ```
39
+
40
+ ## GitHub Copilot / VS Code
41
+
42
+ Workspace `.vscode/mcp.json`, or your VS Code user MCP config:
43
+
44
+ ```json
45
+ {
46
+ "servers": {
47
+ "logwork": {
48
+ "type": "stdio",
49
+ "command": "node",
50
+ "args": ["/Users/<user>/.logwork-cli/bin/logwork.mjs", "mcp"]
51
+ }
52
+ }
53
+ }
54
+ ```
55
+
56
+ ## Claude Code
57
+
58
+ ```bash
59
+ claude mcp add --transport stdio logwork -- node "/Users/<user>/.logwork-cli/bin/logwork.mjs" mcp
60
+ ```
61
+
62
+ From Windows PowerShell:
63
+
64
+ ```powershell
65
+ claude mcp add --transport stdio logwork -- node 'C:\Users\<user>\.logwork-cli\bin\logwork.mjs' mcp
66
+ ```
67
+
68
+ Or add the Cursor JSON above to the project `.mcp.json`.
69
+
70
+ Templates are also in [examples/mcp](../examples/mcp/).
71
+
72
+ If you used `logwork-helper` before, delete its old MCP entry. It points at `~/.logwork-helper/mcp-server.mjs`, which is the old runtime.
73
+
74
+ ## Exposed Tools
75
+
76
+ After editing the config, restart or reload the IDE. The server exposes 15 tools. Each one has a title, a description, a described input schema, and MCP annotations (`readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`), so IDEs and agents can tell read-only tools from writes.
77
+
78
+ The server also sends MCP `instructions` that explain the approval rules, the line format and the recommended call order. Most clients pass these to the model automatically.
79
+
80
+ **Writes are two calls to the same tool:**
81
+
82
+ 1. Call the tool **without `confirm`**. It returns a preview: a `batchId` (for `log_work` and `log_jira_work`) or a `previewId` (for the entry tools), plus a `summary`. Show the summary to the user.
83
+ 2. After explicit approval, call the same tool **again with only that id and `confirm: true`**.
84
+
85
+ The apply call writes the cached, approved preview as-is. If the apply call also carries content fields (such as `text`, `hours` or `description`), it is rejected rather than silently ignored. To change values, preview again.
86
+
87
+ Previews expire after 1 hour. They are also lost when the server restarts.
88
+
89
+ | Group | Tool | Kind | Purpose |
90
+ |---|---|---|---|
91
+ | Read | `get_logwork` | read-only | Booked vs logged RO hours by day and project, with entries (`logworkId`, worklog task, description, status). |
92
+ | Read | `list_projects` | read-only | RO memberships (`projectMemberId`, `projectId`, `projectName`) and local mappings. |
93
+ | Read | `list_tasks` | read-only | RO worklog task catalog for one `projectId`: id, name, type of work, and when to use each task. |
94
+ | Read | `get_jira_issue` | read-only | Jira issue key, summary and status. |
95
+ | Read | `reconcile` | read-only | Compare RO and Jira hours by day. Never writes. |
96
+ | Read | `get_history` | read-only (local) | Local apply history. Contains no credentials. |
97
+ | RO write | `log_work` | two-call write | Create new RO entries from a weekly block (worklog task + description). |
98
+ | RO write | `edit_entry` | two-call, destructive | Change hours, worklog task, type of work or description of a submitted or approved entry. Apply replaces the entry. |
99
+ | RO write | `resubmit_entry` | two-call write | Fix and resubmit a rejected entry (hours, type, description, note to PM). |
100
+ | RO write | `delete_entry` | two-call, destructive | Delete a submitted or approved entry. |
101
+ | Jira write | `log_jira_work` | two-call write | Create Jira worklogs. The description becomes the worklog comment. |
102
+ | Config | `map_project` | local write, `confirm` | Map ticket prefixes or keywords to an RO project (`.logwork.json`). |
103
+ | Config | `reminder` | `action`: status / enable / disable / test | Native OS reminder. Every action except `status` needs `confirm: true`. |
104
+ | Config | `update` | `action`: check / install | npm self-update. `install` needs `confirm: true`. |
105
+ | Auth | `login` | local | `target: "ro"` (default) opens or explains a terminal login. `target: "jira"` explains how to save a PAT. Never accepts credentials. |
106
+
107
+ ### Tool Name Changes From logwork-helper
108
+
109
+ | logwork-helper (before 0.3.0) | logwork-cli |
110
+ |---|---|
111
+ | `preview_logwork_batch`, `apply_logwork_batch` | `log_work` |
112
+ | `query_logwork` | `get_logwork` |
113
+ | `list_logwork_projects` | `list_projects` |
114
+ | `list_worklog_tasks` | `list_tasks` |
115
+ | `preview_ro_logwork_edit`, `apply_ro_logwork_edit` | `edit_entry` |
116
+ | `preview_ro_logwork_resubmit`, `apply_ro_logwork_resubmit` | `resubmit_entry` |
117
+ | `preview_ro_logwork_delete`, `apply_ro_logwork_delete`, `delete_ro_logwork_entry` | `delete_entry` |
118
+ | `preview_jira_worklog_batch`, `apply_jira_worklog_batch` | `log_jira_work` |
119
+ | `reconcile_logwork` | `reconcile` |
120
+ | `query_apply_history` | `get_history` |
121
+ | `upsert_project_mapping` | `map_project` |
122
+ | `start_auth_login`, `start_jira_auth` | `login` (`target: "ro"` or `"jira"`) |
123
+ | `get_logwork_reminder`, `configure_logwork_reminder`, `test_logwork_reminder` | `reminder` (`action`) |
124
+ | `check_for_updates`, `apply_update` | `update` (`action`) |
125
+
126
+ The structured `batch` / `preview` echo parameters of the old apply tools are gone. Apply calls use only the id.
127
+
128
+ ## Logwork Line Format
129
+
130
+ `log_work` and `log_jira_work` take the same text:
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-227)
136
+ Tuesday, 02 Jun 2026
137
+ +2.5 Bug Fix | Password reset validation and UI improvements (SCB-228)
138
+ ```
139
+
140
+ - **Day heading:** `<Weekday>, <DD> <Mon> <YYYY>`.
141
+ - **Entry:** `+<hours> <worklog task> | <description>`.
142
+ - `<worklog task>` is a Resource Optimiser worklog task name from `list_tasks` (case-insensitive exact match), or `#<id>`.
143
+ - `<description>` is free text. Resource Optimiser stores it as the entry `description`, and Jira uses it as the worklog comment. Only the first `|` splits the line; any later `|` stays in the description.
144
+ - **Lines without `|`** are still accepted:
145
+ - If the whole text is a catalog task name, the entry is written without a description and the preview shows a warning.
146
+ - Otherwise, pass `defaultWorklogTask` (for example `"Other Activities"`) to the `log_work` preview call, and the text becomes the description. Without it, the entry is unresolved with reason `worklog_task_required` and the preview lists `availableTaskNames`.
147
+ - **Jira lines** need exactly one issue key, such as `SCB-213`.
148
+
149
+ If a tool says auth is required, the assistant calls `login`, or you can run `logwork login` yourself. For Jira, the assistant calls `login` with `target: "jira"`, or you run `logwork login jira`.
150
+
151
+ The Jira prompt accepts a Personal Access Token in the terminal only. Neither login accepts credentials through MCP.
152
+
153
+ Do not paste passwords, 2FA codes, Bearer tokens, cookies, or raw auth logs into AI chat.
154
+
155
+ ## Verify Setup
156
+
157
+ Use these prompts after your IDE sees the `logwork` server:
158
+
159
+ ```text
160
+ Check my logwork for this week.
161
+ ```
162
+
163
+ ```text
164
+ Which Resource Optimiser project should this repo log work to?
165
+ ```
166
+
167
+ ```text
168
+ Log 2 hours today for SCB-213 "maintenance mode UI" as Feature Development, with a clear description. Preview first and wait for my approval.
169
+ ```
170
+
171
+ ```text
172
+ Set up the SCB ticket mapping to project 2621A-SIT-HTML BUILDER-PRJ.
173
+ ```
174
+
175
+ ## Common MCP Workflows
176
+
177
+ ### Query Logwork
178
+
179
+ Ask your assistant:
180
+
181
+ ```text
182
+ List the days and projects I logged work for this week, including entry details.
183
+ ```
184
+
185
+ The assistant calls `get_logwork`. Supported periods are `today`, `yesterday`, `this_week`, `last_week`, `this_month` and `last_month`. This is read-only.
186
+
187
+ ### Reconcile Resource Optimiser And Jira
188
+
189
+ ```text
190
+ Compare my Resource Optimiser and Jira worklogs for this week. Show daily differences and do not write anything.
191
+ ```
192
+
193
+ The assistant calls `reconcile` with `period: "this_week"`. Custom dates are intentionally not exposed.
194
+
195
+ The result includes:
196
+ - daily booked, RO and Jira totals;
197
+ - issue-level differences;
198
+ - entries that cannot be verified because they do not contain exactly one Jira key;
199
+ - high-confidence correction suggestions.
200
+
201
+ A suggestion is not an approved write. It still goes through the two-call write of `log_work`, `edit_entry` or `log_jira_work`.
202
+
203
+ ### Log Work To Resource Optimiser
204
+
205
+ 1. Optional: call `get_logwork` to see booked and logged hours.
206
+ 2. Call `list_projects`, then `list_tasks` with the `projectId`, to pick valid worklog task names.
207
+ 3. Call `log_work` with `text`.
208
+ 4. Show the summary and ask for approval. The summary shows each line as `project - worklog task | description`, plus an approval checklist with the total hours, date range and per-project breakdown.
209
+ 5. Call `log_work` with `batchId` and `confirm: true`. Add `allowUnbooked: true` only if the user agreed to log to a project that is not booked on that date.
210
+
211
+ The `batchId` changes whenever a description or `defaultWorklogTask` changes, so an approval always covers the exact text that will be written. If an entry is unresolved, re-preview with `projectOverrides` (preview entry id → `projectMemberId`), or save a mapping with `map_project`.
212
+
213
+ Each preview entry contains:
214
+ - `taskName`: the resolved RO worklog task;
215
+ - `worklogTaskId`;
216
+ - `description`;
217
+ - `descriptionMissing`;
218
+ - `taskResolution.reason`.
219
+
220
+ | `taskResolution.reason` / entry `reason` | Meaning | Fix |
221
+ |---|---|---|
222
+ | `worklog_task_match` | Task resolved from the text before `\|` (or the whole line). | None. |
223
+ | `default_worklog_task` | The line had no `\|`, so `defaultWorklogTask` was used and the line became the description. | None. |
224
+ | `worklog_task_required` | The line had no `\|` and is not a catalog task. | Add `<task> \|`, or pass `defaultWorklogTask`. See `availableTaskNames`. |
225
+ | `task_not_found` | The task before `\|` is not in the catalog. | Use a name from `suggestedTaskNames` or `availableTaskNames`. |
226
+ | `task_lookup_failed` | The catalog request failed. | Retry, or check auth. |
227
+
228
+ Apply sends `POST /logwork/entries` with `worklog_task_id`, `effort_hours`, `logdate`, `type_of_work` and `description`, plus `project_id` when the task is a shared default. New entries are approved immediately. `log_work` never writes Jira.
229
+
230
+ ### Edit, Resubmit, Or Delete An Existing RO Entry
231
+
232
+ Get the `logworkId` from `get_logwork` first.
233
+
234
+ ```text
235
+ RO logwork 304032 should be a Bug Fix with description "Fix date picker timezone (SAP-42)". Keep hours, project, and date. Show me the diff and ask before applying.
236
+ ```
237
+
238
+ 1. Call `edit_entry` with `logworkId: 304032`, `taskName: "Bug Fix"` and `description: "Fix date picker timezone (SAP-42)"`.
239
+ 2. Show the original and updated fields. Project and date are shown as unchanged.
240
+ 3. Ask for explicit approval.
241
+ 4. Call `edit_entry` with the returned `previewId` and `confirm: true`.
242
+
243
+ The optional changes are:
244
+ - `hours`
245
+ - `taskName`: a catalog name from `list_tasks`, or `#<id>`.
246
+ - `description`
247
+ - `typeOfWork`
248
+
249
+ Pass at least one. Omitted fields keep their current value. The exception is `typeOfWork`: if it is omitted and the task changes, it follows the new task's catalog type.
250
+
251
+ RO has no staff edit endpoint. `PATCH /logwork/pm/entries/:id/edit-approve` exists but is PM-only. So apply **replaces** the entry:
252
+
253
+ 1. It re-reads the entry and blocks if the entry changed after the preview.
254
+ 2. It creates the corrected entry with `POST /logwork/entries`.
255
+ 3. It deletes the original with `DELETE /logwork/entries/:id`.
256
+ 4. It verifies the new entry.
257
+
258
+ If the create fails, the original is untouched. If the delete fails, the new entry is rolled back.
259
+
260
+ Deleting needs no approval, and the new entry is approved immediately, so the edit takes effect at once. Because the entry id changes, the result returns both `originalLogworkId` and `newLogworkId`.
261
+
262
+ Which tool to use:
263
+
264
+ | Entry | Tool |
265
+ |---|---|
266
+ | Rejected, needs fixing | `resubmit_entry`: change hours, type of work, description, or add a note to the PM. |
267
+ | No longer needed | `delete_entry`: works only on submitted or approved entries. |
268
+ | On a locked day, created by Jira, or owned by another user | Edit is blocked. |
269
+
270
+ `edit_entry` and `delete_entry` carry `destructiveHint: true`.
271
+
272
+ ### Log Work To Jira
273
+
274
+ Jira worklogs are separate from Resource Optimiser logwork. Log in first with `logwork login jira`.
275
+
276
+ Each line must include exactly one Jira issue key. The RO worklog task before `|` is ignored by Jira. A line without `|` uses the whole text as the comment.
277
+
278
+ 1. Call `log_jira_work` with `text`.
279
+ 2. Show the summary and ask for approval. The summary includes the ready, duplicate, missing-ticket, multi-ticket and lookup-failed counts; the issue summary and status; and the final `started` and comment values.
280
+ 3. Call `log_jira_work` with `batchId` and `confirm: true`.
281
+
282
+ Duplicates block apply, and there is no override option. A worklog counts as a duplicate when it has the same short marker (`#lh:<hash>`), or the same issue, date, duration and normalized comment. Legacy `[logwork-helper:...]` markers in older comments are still recognized.
283
+
284
+ Each worklog is written with these values:
285
+
286
+ ```text
287
+ started: 09:00 Asia/Ho_Chi_Minh on the entry date
288
+ timeSpentSeconds: hours * 3600
289
+ comment: description (text after "|", or the whole line) plus short marker, for example #lh:8f3a91c0
290
+ adjustEstimate: leave
291
+ ```
292
+
293
+ Override `started` with `LOGWORK_JIRA_STARTED_TIME=HH:mm` and the timezone with `LOGWORK_TIMEZONE=<IANA timezone>`.
294
+
295
+ ### Both
296
+
297
+ For the same text, run both previews: `log_work` and `log_jira_work`. Show both summaries, then apply each one with its own approval.
298
+
299
+ The two applies are intentionally not atomic. `log_work` never writes Jira, and `log_jira_work` never writes Resource Optimiser.
300
+
301
+ ### History, Updates, Reminder
302
+
303
+ - **History:** `get_history` reads the sanitized local ledger. The `both` filter returns records created by the combined Both flow.
304
+ - **Updates:**
305
+ 1. Call `update` with `action: "check"` (read-only) and show the target version.
306
+ 2. After approval, call `update` with `action: "install"`, `version` and `confirm: true`.
307
+ 3. Reconnect MCP afterwards.
308
+
309
+ Install re-checks npm, accepts only npm latest, and never accepts a registry, package or shell command.
310
+ - **Reminder:**
311
+ - `reminder` with `action: "status"` is read-only.
312
+ - `enable` (with optional `time` and `target`), `disable` and `test` need `confirm: true` after approval.
313
+ - macOS uses launchd and Windows uses Task Scheduler.
314
+ - Reminder tools never accept credentials, scheduler commands or executable paths.
315
+
316
+ ### Project Mapping
317
+
318
+ You do not need to create the mapping file by hand. When a preview cannot resolve a ticket like `SCB-213`, the assistant calls `list_projects`. After you approve, it calls `map_project` with `tickets`, an optional `keywords`, and `confirm: true`.
319
+
320
+ Mappings are stored in one of two places:
321
+ - **User scope (default):** `~/.logwork-cli/.logwork.json`.
322
+ - **Project scope:** `.logwork.json` in the current repo. A repo that still has `.logwork-helper.json` keeps using that file until a `.logwork.json` exists.
323
+
324
+ ```json
325
+ {
326
+ "projectMappings": [
327
+ {
328
+ "projectName": "2621A-SIT-HTML BUILDER-PRJ",
329
+ "projectMemberId": 5234,
330
+ "tickets": ["SCB"],
331
+ "keywords": ["question bank", "programme", "cluster"]
332
+ }
333
+ ]
334
+ }
335
+ ```
336
+
337
+ This file stores matching hints only. It never stores tokens.
338
+
339
+ ### Allow Unbooked Logging
340
+
341
+ Sometimes a line matches one of your project memberships, but that project is not booked for the date. The preview then marks the entry `UNBOOKED`.
342
+
343
+ Only allow this when the matched project is correct. Apply with:
344
+
345
+ ```json
346
+ { "batchId": "<from preview>", "confirm": true, "allowUnbooked": true }
347
+ ```