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.
- package/LICENSE +11 -0
- package/README.md +287 -2
- package/RELEASE.md +89 -0
- package/bin/logwork.mjs +101 -0
- package/commands/auth.mjs +227 -0
- package/commands/delete.mjs +69 -0
- package/commands/doctor.mjs +24 -0
- package/commands/edit.mjs +88 -0
- package/commands/history.mjs +62 -0
- package/commands/query.mjs +52 -0
- package/commands/quick.mjs +163 -0
- package/commands/reconcile.mjs +55 -0
- package/commands/release.mjs +77 -0
- package/commands/reminder.mjs +172 -0
- package/commands/setup.mjs +504 -0
- package/commands/tui.mjs +50 -0
- package/commands/update.mjs +161 -0
- package/docs/advanced.md +334 -0
- package/docs/mcp-setup.md +347 -0
- package/docs/operations-guide.md +587 -0
- package/docs/recipes.md +259 -0
- package/docs/security.md +151 -0
- package/examples/mcp/antigravity.mcp_config.json +8 -0
- package/examples/mcp/codex.config.toml +5 -0
- package/examples/mcp/copilot.mcp.json +9 -0
- package/lib/api-auth.mjs +1259 -0
- package/lib/api.mjs +1422 -0
- package/lib/apply-ledger.mjs +227 -0
- package/lib/atomic-file.mjs +24 -0
- package/lib/auth-diagnostics.mjs +113 -0
- package/lib/auth-errors.mjs +22 -0
- package/lib/auth-redaction.mjs +78 -0
- package/lib/auth-terminal.mjs +97 -0
- package/lib/auth.mjs +323 -0
- package/lib/batch-parser.mjs +145 -0
- package/lib/batch-workflow.mjs +842 -0
- package/lib/config.mjs +191 -0
- package/lib/credential-store.mjs +130 -0
- package/lib/diagnostics.mjs +307 -0
- package/lib/entrypoint.mjs +14 -0
- package/lib/file-lock.mjs +44 -0
- package/lib/http.mjs +125 -0
- package/lib/jira-api.mjs +258 -0
- package/lib/jira-auth.mjs +203 -0
- package/lib/jira-workflow.mjs +523 -0
- package/lib/keychain.mjs +105 -0
- package/lib/legacy-migration.mjs +66 -0
- package/lib/list-navigation.mjs +19 -0
- package/lib/logwork-config.mjs +199 -0
- package/lib/logwork-f03-enrich.mjs +41 -0
- package/lib/macos.mjs +33 -0
- package/lib/manual-apply-state.mjs +35 -0
- package/lib/manual-commands.mjs +294 -0
- package/lib/manual-drafts.mjs +154 -0
- package/lib/manual-ink-app.mjs +1654 -0
- package/lib/manual-ink-auth.mjs +349 -0
- package/lib/manual-ink-ui.mjs +675 -0
- package/lib/manual-input.mjs +21 -0
- package/lib/manual-logwork-wizard.mjs +310 -0
- package/lib/manual-mcp.mjs +187 -0
- package/lib/manual-repl.mjs +1037 -0
- package/lib/manual-targets.mjs +78 -0
- package/lib/mcp-server.mjs +793 -0
- package/lib/os-notification.mjs +105 -0
- package/lib/package-info.mjs +17 -0
- package/lib/paths.mjs +68 -0
- package/lib/project-identity.mjs +66 -0
- package/lib/project-mapping-workflow.mjs +309 -0
- package/lib/project-resolver.mjs +373 -0
- package/lib/query-workflow.mjs +553 -0
- package/lib/reconciliation-workflow.mjs +446 -0
- package/lib/release-doctor.mjs +448 -0
- package/lib/reminder-config.mjs +71 -0
- package/lib/reminder-scheduler.mjs +301 -0
- package/lib/reminder-service.mjs +118 -0
- package/lib/reminder-state.mjs +38 -0
- package/lib/reminder-workflow.mjs +299 -0
- package/lib/ro-delete-args.mjs +38 -0
- package/lib/ro-delete-workflow.mjs +115 -0
- package/lib/ro-edit-args.mjs +142 -0
- package/lib/ro-edit-workflow.mjs +632 -0
- package/lib/ro-entry-reader.mjs +56 -0
- package/lib/ro-resubmit-workflow.mjs +134 -0
- package/lib/terminal-auth-prompts.mjs +120 -0
- package/lib/ui.mjs +133 -0
- package/lib/update-service.mjs +350 -0
- package/lib/util.mjs +66 -0
- package/lib/windows-credential-manager.mjs +260 -0
- package/lib/worklog-task-resolver.mjs +113 -0
- package/package.json +72 -4
- package/setup.sh +22 -0
package/docs/advanced.md
ADDED
|
@@ -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
|
+
```
|