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,587 @@
1
+ # Integrated Operations Guide
2
+
3
+ This guide describes the complete Resource Optimiser and Jira workflow available through the terminal CLI and MCP server. It also covers project mapping, reconciliation, apply history, native reminders, self-update, and release checks.
4
+
5
+ ## Initial Setup
6
+
7
+ Requirements:
8
+
9
+ - macOS or Windows 10/11.
10
+ - Node.js 22 or newer.
11
+ - npm.
12
+ - A Resource Optimiser account.
13
+ - A Jira Personal Access Token when Jira features are used.
14
+
15
+ Install and prepare the stable local runtime:
16
+
17
+ ```bash
18
+ npm install -g logwork-cli
19
+ logwork setup
20
+ ```
21
+
22
+ Authenticate each target from Terminal:
23
+
24
+ ```bash
25
+ logwork login
26
+ logwork login jira
27
+ ```
28
+
29
+ Check both sessions without printing credentials:
30
+
31
+ ```bash
32
+ logwork status
33
+ ```
34
+
35
+ Upgrading from `logwork-helper`: see [Upgrading from logwork-helper](../README.md#upgrading-from-logwork-helper).
36
+
37
+ Resource Optimiser credentials and Jira PATs are never accepted by MCP tools. The final sessions are stored in macOS Keychain or Windows Credential Manager.
38
+
39
+ ## Capability Map
40
+
41
+ | Operation | Terminal CLI | `logwork` UI | MCP tool | Writes external data |
42
+ | --- | --- | --- | --- | --- |
43
+ | Query RO | `logwork query` | `/query <period>` | `get_logwork` | No |
44
+ | Log RO | `logwork quick` (one entry) | `/logwork ro` | `log_work` | Apply call only |
45
+ | Edit existing RO entry | `logwork edit` | `/edit-logwork` | `edit_entry` | Apply call only |
46
+ | Resubmit rejected RO | - | - | `resubmit_entry` | Apply call only |
47
+ | Delete RO entry | `logwork delete` | - | `delete_entry` | Apply call only |
48
+ | Log Jira | - | `/logwork jira` | `log_jira_work` | Apply call only |
49
+ | Log Both | - | `/logwork both` | `log_work` + `log_jira_work` separately | Apply calls only |
50
+ | Project mapping | - | `/projects`, `/map` | `list_projects`, `map_project` | Local config only |
51
+ | RO worklog task catalog | - | - | `list_tasks` | No |
52
+ | Reconcile RO/Jira | `logwork reconcile` | `/reconcile` | `reconcile` | No |
53
+ | Apply history | `logwork history` | `/history` | `get_history` | No |
54
+ | Reminder | `logwork reminder` | - | `reminder` (`action`) | OS schedule only |
55
+ | Update | `logwork update` | Startup notice | `update` (`action`) | Local runtime only |
56
+ | Login | `logwork login\|logout\|status` | `/auth`, `/status` | `login` (explains terminal login) | OS credential store |
57
+ | Diagnostics | `logwork doctor` | `/diagnostics` | - | Local file only |
58
+ | Release preflight | `logwork release doctor` | - | - | No |
59
+
60
+ MCP writes are two calls to the same tool. The first call, without `confirm`, returns a preview with a `batchId` or `previewId`. The second call passes that id with `confirm: true`. An apply call that also carries content fields is rejected.
61
+
62
+ All apply, mapping, reminder configuration, reminder test, and update operations require explicit confirmation. Query, preview, reconciliation, history, status, and update check operations are read-only.
63
+
64
+ ## Target Routing
65
+
66
+ ### Resource Optimiser
67
+
68
+ Use the RO flow when the intent is Resource Optimiser logwork:
69
+
70
+ ```text
71
+ /logwork ro
72
+ ```
73
+
74
+ MCP uses:
75
+
76
+ 1. `list_projects` and `list_tasks`, to choose a valid worklog task.
77
+ 2. `log_work` with `text`, which returns the preview.
78
+ 3. `log_work` with `batchId` and `confirm: true`, after approval.
79
+
80
+ RO resolves each task to a project using the approved preview override, local ticket/keyword mappings, booked projects, and available project memberships. Jira is not written by this flow.
81
+
82
+ Creating new RO logwork uses `POST /logwork/entries`. Every RO entry has two text parts:
83
+
84
+ - **Worklog task**: a catalog item from `GET /logwork/tasks` and `/logwork/tasks/defaults` for the matched project (for example `Feature Development`, `Code Review & Refactoring`). Sent as `worklog_task_id`.
85
+ - **Description**: free text describing the actual work (for example `Implement maintenance mode UI (SCB-213)`). Sent as `description`.
86
+
87
+ Write each line as `+<hours> <worklog task> | <description>`. The worklog task must match the RO catalog name exactly (case-insensitive) or be written as `#<id>`. A line without `|` is treated as a catalog task name when it matches one (no description is written and the preview warns); otherwise it becomes the description under MCP `defaultWorklogTask`, or the entry stays unresolved with reason `worklog_task_required` and `availableTaskNames`. **Worklog task** (catalog) is not the same as **type of work** (`create`, `correct`, `improve`, `other`) on the log entry.
88
+
89
+ New entries default to `type_of_work: other` when the matched catalog task has no `type_of_work`. When the RO task row defines `type_of_work`, preview copies it onto the entry unless MCP `typeOfWork` overrides the whole batch.
90
+
91
+ The optional `log_work` preview input `typeOfWork` applies to every line in the batch and overrides per-task catalog defaults.
92
+
93
+ The optional `log_work` preview input `defaultWorklogTask` (name or `#<id>`) supplies the worklog task for lines without `|` that are not catalog task names. The `batchId` includes this value and every description, so approval always covers the exact payload.
94
+
95
+ ### Staff API surface (F03 vs legacy)
96
+
97
+ | Intent | HTTP | Used by helper |
98
+ | --- | --- | --- |
99
+ | Create entry (approved) | `POST /logwork/entries` | `log_work`, `logwork quick` |
100
+ | List worklog tasks | `GET /logwork/tasks`, `/logwork/tasks/defaults` | Batch preview task resolution |
101
+ | Day view (status, lock) | `GET /logwork/day` | `get_logwork` entry enrichment, edit reads |
102
+ | Weekly summary | `GET /logwork/weekly` | Available in API client; booked hours still come from legacy timesheet |
103
+ | Rejected list | `GET /logwork/rejected` | Optional query enrichment (`includeRejected` when wired) |
104
+ | Resubmit rejected | `PATCH /logwork/entries/:id/resubmit` | `resubmit_entry` |
105
+ | Delete submitted/approved | `DELETE /logwork/entries/:id` | `delete_entry`, `logwork delete` |
106
+ | Booked + logged range | `GET /member-logtime/timesheet` | `get_logwork`, batch booked-project resolution |
107
+ | Day task detail | `GET /member-logtime` | `get_logwork` entry lines |
108
+ | Edit hours/task/type/description | `POST /logwork/entries` then `DELETE /logwork/entries/:id` (replace) | `edit_entry`, `logwork edit` |
109
+
110
+ RO F03 has no staff edit endpoint. `PATCH /logwork/pm/entries/:id/edit-approve` is PM-only, so the helper edits by replacing the entry. The legacy `PATCH /member-logtime` `update_data` is no longer used by the edit flow. It only changed the `task_name` text and never remapped `worklog_task_id` or `description`.
111
+
112
+ ### Edit Existing Resource Optimiser Logwork
113
+
114
+ Use the logwork entry ID returned by an RO query:
115
+
116
+ ```bash
117
+ logwork edit 304032 --hours 0.5
118
+ logwork edit 304032 --task "Bug Fix" --desc "Fix date picker timezone (SAP-42)"
119
+ logwork edit 304032 --type improve
120
+ ```
121
+
122
+ The long forms `--task-name` and `--description` are also accepted. The terminal UI equivalent is:
123
+
124
+ ```text
125
+ /edit-logwork 304032 --hours 0.5 --task Bug Fix --desc Fix date picker timezone (SAP-42)
126
+ ```
127
+
128
+ MCP uses two calls to `edit_entry`:
129
+
130
+ 1. A preview call with `logworkId` and at least one of `hours`, `taskName` (catalog name or `#<id>`), `description`, or `typeOfWork`.
131
+ 2. An apply call with the returned `previewId` and `confirm: true`.
132
+
133
+ How the edit is processed:
134
+
135
+ 1. **Read.** The legacy `GET /member-logtime/:id` returns the date, owner, and Jira link. `GET /logwork/day?date=` returns the F03 fields: status, `worklog_task_id`, `type_of_work`, and `description`. The project-member list maps `project_member_id` to `project_id`.
136
+ 2. **Resolve.** The worklog task is resolved against `GET /logwork/tasks` plus `/logwork/tasks/defaults` for the project. When the task changes and `typeOfWork` is omitted, the new task's catalog `type_of_work` is used. Otherwise the current type is kept.
137
+ 3. **Apply.** It re-checks the original revision, then:
138
+ - creates the corrected entry with `POST /logwork/entries`;
139
+ - deletes the original with `DELETE /logwork/entries/:id`;
140
+ - verifies the new entry.
141
+
142
+ If the create fails, nothing changed. If the delete fails, the new entry is deleted again (rollback). If that rollback also fails, the error names both ids.
143
+
144
+ If the create response has no id, the new entry is looked up in `/logwork/day`. If it still can't be found, the original is **not** deleted.
145
+
146
+ Deleting needs no PM approval and the new entry is approved immediately, so the edit takes effect at once. The `is_locked: true` flag RO puts on approved entries does not block the delete. Only a locked day (`isLocked` from `/logwork/day`) blocks an edit. The result returns `originalLogworkId` and `newLogworkId`. Project and date never change.
147
+
148
+ These entries are blocked:
149
+ - rejected entries (use resubmit),
150
+ - entries on locked days,
151
+ - entries owned by another user,
152
+ - entries created by Jira.
153
+
154
+ In dry run (`LOGWORK_DRY_RUN=1`), apply returns both requests without writing.
155
+
156
+ ### Delete mistaken Resource Optimiser logwork
157
+
158
+ Use the entry ID from `logwork query`, `get_logwork`, or the RO UI. Only **submitted** or **approved** entries can be soft-deleted. **Rejected** entries must be resubmitted instead (`resubmit_entry`). Deleting needs no PM approval.
159
+
160
+ ```bash
161
+ logwork delete 290364
162
+ logwork delete 290364 --yes --json
163
+ ```
164
+
165
+ MCP uses two calls to `delete_entry`:
166
+
167
+ 1. A preview call with `logworkId`.
168
+ 2. An apply call with the returned `previewId` and `confirm: true`.
169
+
170
+ The apply call re-checks the entry revision before sending `DELETE`.
171
+
172
+ The API call is `DELETE /logwork/entries/:id` (soft-delete via `deleted_date`).
173
+
174
+ ### Jira
175
+
176
+ Use the Jira flow when the intent is a Jira worklog:
177
+
178
+ ```text
179
+ /logwork jira
180
+ ```
181
+
182
+ MCP uses:
183
+
184
+ 1. `log_jira_work` with `text`, which returns the preview.
185
+ 2. `log_jira_work` with `batchId` and `confirm: true`, after approval.
186
+
187
+ Every entry must contain exactly one Jira issue key. RO is not written by this flow.
188
+
189
+ ### Both
190
+
191
+ Use the combined terminal flow when the same date/tasks should be sent to both systems:
192
+
193
+ ```text
194
+ /logwork both
195
+ ```
196
+
197
+ The flow creates two independent previews and requests two approvals:
198
+
199
+ 1. Preview and optionally apply Resource Optimiser.
200
+ 2. Preview and optionally apply Jira.
201
+
202
+ The operation is not atomic. If RO succeeds and Jira fails, RO is not rolled back. Apply history records the result of each target with `flowTarget: both` so partial outcomes remain visible.
203
+
204
+ MCP has no unified Both tool. The assistant previews with both `log_work` and `log_jira_work`, presents both summaries, and requests approval for each apply separately.
205
+
206
+ ## Input Format
207
+
208
+ MCP and pasted weekly text use date headings followed by one task per line:
209
+
210
+ ```text
211
+ Monday, 13 Jul 2026
212
+ +2 Feature Development | Maintenance mode management (SCB-213)
213
+ +1 Feature Development | Update system page (SCB-214)
214
+ Tuesday, 14 Jul 2026
215
+ +1.5 Bug Fix | Fix password reset regression (SCB-215)
216
+ ```
217
+
218
+ Rules:
219
+
220
+ - A date heading uses `Weekday, DD Mon YYYY`.
221
+ - A task uses `+<hours> <worklog task> | <description>`. Only the first `|` splits the line.
222
+ - For RO, `<worklog task>` must be an RO catalog task (`list_tasks`) and `<description>` is stored as the entry description.
223
+ - For Jira, `<worklog task>` is ignored and `<description>` becomes the worklog comment. Lines without `|` use the whole text.
224
+ - Hours must be greater than zero and may be decimal.
225
+ - RO can accept entries without a Jira issue key when a project can still be resolved.
226
+ - Jira requires exactly one key such as `SCB-213` in every entry.
227
+ - Jira blocks entries with no key or multiple keys.
228
+
229
+ The terminal wizard selects one date for the current session. It accepts the same task line format without requiring a pasted date heading.
230
+
231
+ ## Resource Optimiser Processing Example
232
+
233
+ Input:
234
+
235
+ ```text
236
+ Monday, 13 Jul 2026
237
+ +2 Feature Development | Maintenance mode management (SCB-213)
238
+ +1 Feature Development | Update system page (SCB-214)
239
+ ```
240
+
241
+ Processing:
242
+
243
+ 1. Parse the date, hours, worklog task, description, and issue keys.
244
+ 2. Load booked RO projects and project memberships for the date.
245
+ 3. Apply user/project ticket and keyword mappings (matched against the whole line).
246
+ 4. Resolve the worklog task in the project catalog and attach `worklogTaskId` and `description`.
247
+ 5. Mark each entry as resolved, resolved but unbooked, or unresolved.
248
+ 6. Return an approval summary. No work is submitted during preview.
249
+
250
+ Illustrative ready preview:
251
+
252
+ ```text
253
+ Logwork preview:
254
+ - 2026-07-13: +2h 2621A-SIT-HTML BUILDER-PRJ - Feature Development | Maintenance mode management (SCB-213) (via config_ticket, confidence 1)
255
+ - 2026-07-13: +1h 2621A-SIT-HTML BUILDER-PRJ - Feature Development | Update system page (SCB-214) (via config_ticket, confidence 1)
256
+ Approval checklist: 2 entries, 3h total, 2026-07-13.
257
+ Projects: 2621A-SIT-HTML BUILDER-PRJ: 3h.
258
+ Ready to apply.
259
+ ```
260
+
261
+ After explicit approval, the apply result is similar to:
262
+
263
+ ```text
264
+ Logwork submitted:
265
+ Submitted 2 entries, 3h total.
266
+ - 2026-07-13: +2h 2621A-SIT-HTML BUILDER-PRJ - Feature Development | Maintenance mode management (SCB-213)
267
+ - 2026-07-13: +1h 2621A-SIT-HTML BUILDER-PRJ - Feature Development | Update system page (SCB-214)
268
+ ```
269
+
270
+ If a valid membership is not booked for the selected date, preview prefixes the entry with `UNBOOKED`. Applying it requires a second decision through `allowUnbooked: true`. An unresolved project always blocks apply.
271
+
272
+ ## Jira Processing Example
273
+
274
+ For each entry, Jira preview:
275
+
276
+ 1. Extracts exactly one issue key.
277
+ 2. Calls Jira to validate issue existence and access.
278
+ 3. Loads existing issue worklogs.
279
+ 4. Blocks duplicates by helper marker or by matching issue, date, duration, and normalized task comment.
280
+ 5. Builds and stores the exact approved payload.
281
+
282
+ Illustrative ready preview:
283
+
284
+ ```text
285
+ Jira worklog preview: ready. 2 entries, 3h total.
286
+ Counts: ready 2, duplicate 0, missing ticket 0, multiple tickets 0, lookup failed 0.
287
+ - 2026-07-13: +2h SCB-213 - Maintenance mode management (SCB-213) -> ready
288
+ Issue: Maintenance mode management [In Progress]
289
+ Started: 2026-07-13T09:00:00.000+0700
290
+ Comment: Maintenance mode management (SCB-213) | #lh:8f3a91c0
291
+ - 2026-07-13: +1h SCB-214 - Update system page (SCB-214) -> ready
292
+ Issue: System page update [To Do]
293
+ Started: 2026-07-13T09:00:00.000+0700
294
+ Comment: Update system page (SCB-214) | #lh:9b18d721
295
+ ```
296
+
297
+ The marker hashes above are examples. The real hash is generated from the approved batch and entry identifiers.
298
+
299
+ The Jira REST payload for the first entry is equivalent to:
300
+
301
+ ```json
302
+ {
303
+ "started": "2026-07-13T09:00:00.000+0700",
304
+ "timeSpentSeconds": 7200,
305
+ "comment": "Maintenance mode management (SCB-213)\n\n#lh:8f3a91c0"
306
+ }
307
+ ```
308
+
309
+ The request uses `adjustEstimate=leave`, so Jira remaining estimate is not changed. The default started time is 09:00 in `Asia/Ho_Chi_Minh`; it can be configured with `LOGWORK_JIRA_STARTED_TIME` and `LOGWORK_TIMEZONE`.
310
+
311
+ After approval, Jira reports each entry independently:
312
+
313
+ ```text
314
+ Jira worklog apply: submitted 2, failed 0.
315
+ - 2026-07-13: SCB-213 +2h -> submitted
316
+ - 2026-07-13: SCB-214 +1h -> submitted
317
+ ```
318
+
319
+ In Jira, the issue worklog displays the current Jira user, logged duration, started date/time, and the comment on two lines:
320
+
321
+ ```text
322
+ Maintenance mode management (SCB-213)
323
+
324
+ #lh:8f3a91c0
325
+ ```
326
+
327
+ The shorter `#lh:<hash>` marker replaces the old visible `[logwork-helper:...]` format from earlier versions. Existing worklogs with the legacy marker are still recognized during duplicate checks.
328
+
329
+ ## Duplicate And Preview Safety
330
+
331
+ RO and Jira MCP previews are cached for one hour, with at most 100 previews per target, and are lost when the server restarts. Apply requires the cached `batchId` or `previewId`. A missing, expired, consumed, or modified preview must be generated again.
332
+
333
+ Jira duplicate detection is blocking and has no override. Apply rechecks worklogs immediately before the first write. If a duplicate appears after preview, the Jira batch is blocked before submission.
334
+
335
+ If a Jira API write fails after earlier entries were submitted, processing stops and the result identifies the submitted entries and the failed entry. Remaining entries are not attempted. The helper never reports a partial batch as fully successful.
336
+
337
+ ## Project Mapping And Similar Content
338
+
339
+ RO project mapping can use:
340
+
341
+ - Jira ticket prefixes, for example `SCB`.
342
+ - Task keywords, for example `maintenance mode`.
343
+ - Explicit project selection during preview.
344
+ - Jira project key/name metadata in the terminal Both flow to rank RO memberships.
345
+
346
+ Example MCP sequence:
347
+
348
+ 1. `get_jira_issue` reads `SCB-213` metadata.
349
+ 2. `list_projects` lists valid RO memberships.
350
+ 3. The assistant compares Jira project metadata and task wording with RO project names/mappings.
351
+ 4. The assistant shows the proposed project and asks for approval.
352
+ 5. `map_project` stores the selected ticket/keyword mapping with `confirm: true`.
353
+ 6. The assistant reruns RO preview.
354
+
355
+ Example mapping:
356
+
357
+ ```json
358
+ {
359
+ "projectMappings": [
360
+ {
361
+ "projectName": "2621A-SIT-HTML BUILDER-PRJ",
362
+ "projectMemberId": 5234,
363
+ "tickets": ["SCB"],
364
+ "keywords": ["maintenance mode", "system page"]
365
+ }
366
+ ]
367
+ }
368
+ ```
369
+
370
+ Content similarity is a suggestion, not an automatic write. The built-in Both flow ranks exact/contained Jira project names, Jira project keys, and meaningful name-token overlap. An MCP assistant can also reason over issue/task text, but it must choose from real RO memberships and obtain confirmation before saving a mapping.
371
+
372
+ ## Reconciliation
373
+
374
+ Reconciliation compares RO and Jira without writing either system:
375
+
376
+ ```bash
377
+ logwork reconcile this-week
378
+ logwork reconcile last-month --json
379
+ ```
380
+
381
+ Supported periods are `today`, `yesterday`, `this-week`, `last-week`, `this-month`, and `last-month`. Custom date inputs are intentionally not supported. The displayed `to` date is the exclusive end of the queried range.
382
+
383
+ Example summary:
384
+
385
+ ```text
386
+ RO / Jira reconciliation: this week (2026-07-13 to 2026-07-20).
387
+
388
+ Date Booked RO Jira Diff Status
389
+ 2026-07-13 8h 7h 6h -1h Task mismatch
390
+ 2026-07-14 8h 8h 8h 0h Matched
391
+
392
+ Total: booked 16h, RO 15h, Jira 14h, difference -1h.
393
+ Days: matched 1, mismatched 1, incomplete 0, unverified 0.
394
+
395
+ High-confidence correction suggestions:
396
+ - 2026-07-13: JIRA +1h SCB-214 - Update system page (SCB-214)
397
+ Create a normal target-specific preview before applying any suggestion.
398
+ ```
399
+
400
+ A correction suggestion is generated only when task-level evidence is strong, including exactly one Jira issue key. It is never applied directly. Use the normal target preview and approval flow.
401
+
402
+ ## Apply History
403
+
404
+ RO and Jira workflow apply outcomes, including submitted, partial, failed, and preview-blocked batches, record a sanitized local result:
405
+
406
+ ```bash
407
+ logwork history
408
+ logwork history --target jira --limit 10
409
+ logwork history --target both --json
410
+ ```
411
+
412
+ Example:
413
+
414
+ ```text
415
+ Apply history: 2 records.
416
+ - 2026-07-15T13:10:00.000Z: jira via both submitted, batch jira_abcd, submitted 2, failed 0, blocked 0, 3h.
417
+ - 2026-07-15T13:09:00.000Z: ro via both submitted, batch batch_efgh, submitted 2, failed 0, blocked 0, 3h.
418
+ ```
419
+
420
+ The ledger stores sanitized task/project/issue/result metadata. It does not store tokens, cookies, raw API responses, passwords, or OTPs.
421
+
422
+ ## Native OS Reminder
423
+
424
+ Enable the default Both reminder at 17:00, Monday-Friday:
425
+
426
+ ```bash
427
+ logwork reminder enable
428
+ ```
429
+
430
+ Other operations:
431
+
432
+ ```bash
433
+ logwork reminder enable --time 18:00 --target ro
434
+ logwork reminder status
435
+ logwork reminder test
436
+ logwork reminder disable
437
+ ```
438
+
439
+ Behavior:
440
+
441
+ - RO compares today's logged hours with booked hours.
442
+ - Jira checks whether the current Jira user has any worklog today.
443
+ - A complete day stays silent.
444
+ - At most one notification is sent per configured workday.
445
+ - Missing auth produces an actionable notification without exposing API details.
446
+ - macOS uses a user `launchd` agent (`sg.vinova.logwork-cli.reminder`).
447
+ - Windows uses an interactive user Task Scheduler task (`Logwork Reminder`).
448
+ - The scheduler runs `node ~/.logwork-cli/bin/logwork.mjs reminder run --home ~/.logwork-cli`.
449
+ - Enabling or disabling the reminder also removes a leftover `logwork-helper` schedule.
450
+
451
+ Example Both notification:
452
+
453
+ ```text
454
+ Logwork hôm nay chưa hoàn tất
455
+ RO: 6/8h, còn thiếu 2h
456
+ Jira: chưa có worklog hôm nay
457
+
458
+ Mở Terminal và chạy: logwork
459
+ ```
460
+
461
+ The notification text is localized in Vietnamese. The OS schedule stores only fixed Node/script paths and reads credentials from the OS credential store when it runs.
462
+
463
+ ## End-User Updates
464
+
465
+ Check the running version against npm latest:
466
+
467
+ ```bash
468
+ logwork update check
469
+ logwork update check --force
470
+ ```
471
+
472
+ Install after confirmation:
473
+
474
+ ```bash
475
+ logwork update install
476
+ ```
477
+
478
+ For a non-interactive terminal, approve the exact published version:
479
+
480
+ ```bash
481
+ logwork update install --version 0.1.11 --yes
482
+ ```
483
+
484
+ The updater:
485
+
486
+ - Uses npm's official registry.
487
+ - Accepts only the package's current `latest` SemVer.
488
+ - Rechecks npm immediately before installation.
489
+ - Copies and verifies the stable local MCP runtime.
490
+ - Preserves credentials, mappings, drafts, history, and reminder config.
491
+
492
+ Restart the terminal and reconnect MCP after a successful update. MCP exposes the same process through `update` with `action: "check"`, then `action: "install"` with `confirm: true`.
493
+
494
+ ## Maintainer Release Flow
495
+
496
+ Update both `package.json` and `package-lock.json` with npm:
497
+
498
+ ```bash
499
+ npm version patch --no-git-tag-version
500
+ ```
501
+
502
+ Use `minor` or `major` instead of `patch` when required by SemVer. Then run:
503
+
504
+ ```bash
505
+ npm run release:check
506
+ ```
507
+
508
+ Commit and sync the version change so the release doctor can verify a clean `main`:
509
+
510
+ ```bash
511
+ git add package.json package-lock.json
512
+ git commit -m "bump version to <version>"
513
+ git push origin main
514
+ logwork release doctor --full
515
+ ```
516
+
517
+ After the release doctor passes:
518
+
519
+ ```bash
520
+ npm publish --access public
521
+ git tag v<version>
522
+ git push origin v<version>
523
+ gh release create v<version> --generate-notes --title "v<version>"
524
+ ```
525
+
526
+ The release doctor checks package version consistency, self-dependencies, clean/synced `main`, npm registry/auth/latest, GitHub auth, tag/release state, tarball artifacts, tests, production audit, package dry run, and whitespace.
527
+
528
+ ## Local State And Credentials
529
+
530
+ | State | macOS/Windows helper-home filename | Sensitive credentials |
531
+ | --- | --- | --- |
532
+ | Installed runtime | `.logwork-cli/` | No |
533
+ | User project mappings | `.logwork-cli/.logwork.json` | No |
534
+ | Manual drafts | `.logwork-cli/manual-drafts.json` | No |
535
+ | Apply history | `.logwork-cli/apply-ledger.json` | No |
536
+ | Update cache | `.logwork-cli/update-state.json` | No |
537
+ | Reminder config/state | `.logwork-cli/reminder.json`, `.logwork-cli/reminder-state.json` | No |
538
+ | RO/Jira sessions | OS credential store, service `logwork-cli` | Yes |
539
+
540
+ The helper home is `~/.logwork-cli` on macOS and `%USERPROFILE%\.logwork-cli` on Windows. `LOGWORK_HOME` overrides it; the older `LOGWORK_HELPER_HOME` is still honored.
541
+
542
+ Migration from `logwork-helper` happens on the first run, unless `LOGWORK_HOME` (or `LOGWORK_HELPER_HOME`) is set:
543
+ - State files are copied once from `~/.logwork-helper`, and `.logwork-helper.json` is renamed to `.logwork.json` on the way. The old directory is left in place. A marker file (`.migrated-from-logwork-helper`) records the copy.
544
+ - Credentials still stored under the old service name (`logwork-helper`) are read once and copied to `logwork-cli`.
545
+ - Logging out clears both credential entries.
546
+
547
+ ## Validation
548
+
549
+ Run the cross-platform suite:
550
+
551
+ ```bash
552
+ npm test
553
+ git diff --check
554
+ npm pack --dry-run
555
+ ```
556
+
557
+ Windows CI additionally runs a real Credential Manager lifecycle test:
558
+
559
+ ```powershell
560
+ npm run test:windows-credential
561
+ ```
562
+
563
+ That integration test stores, reads, and deletes a dedicated test credential. On non-Windows systems it is skipped by design.
564
+
565
+ Recommended end-user checks after installation:
566
+
567
+ 1. Run `logwork --version` and `logwork update check --force`.
568
+ 2. Run `logwork status`.
569
+ 3. Open `logwork` and preview one RO task without applying.
570
+ 4. Preview one Jira task with exactly one issue key without applying.
571
+ 5. Run `logwork reconcile this-week`.
572
+ 6. Run `logwork reminder test`, verify the native notification, then inspect `reminder status`.
573
+ 7. Connect MCP and verify the tool list before testing read-only queries.
574
+
575
+ ## Recovery Rules
576
+
577
+ - Missing RO auth: run `logwork login`.
578
+ - Missing Jira auth: run `logwork login jira`.
579
+ - Unresolved RO project: list memberships, confirm a mapping, and preview again.
580
+ - Jira duplicate: inspect the existing worklog; there is no override.
581
+ - Expired or consumed preview: preview again and request approval again.
582
+ - Partial Both result: inspect `/history both`, then preview only the missing target.
583
+ - npm `E401`: refresh npm login with `npm login --registry=https://registry.npmjs.org/`.
584
+ - Reminder config/scheduler mismatch: rerun `reminder enable` or `reminder disable`.
585
+ - MCP after update: restart or reload the MCP connection.
586
+
587
+ For client configuration details, see [MCP setup](mcp-setup.md). For security boundaries and stored-data details, see [Security and auth](security.md). For copy-ready task recipes, see [Quick recipes](recipes.md).