logwork-cli 0.0.0-stage → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/LICENSE +11 -0
  2. package/README.md +330 -2
  3. package/RELEASE.md +89 -0
  4. package/bin/logwork.mjs +104 -0
  5. package/commands/auth.mjs +227 -0
  6. package/commands/commits.mjs +82 -0
  7. package/commands/delete.mjs +69 -0
  8. package/commands/doctor.mjs +24 -0
  9. package/commands/edit.mjs +88 -0
  10. package/commands/history.mjs +62 -0
  11. package/commands/query.mjs +52 -0
  12. package/commands/quick.mjs +163 -0
  13. package/commands/reconcile.mjs +55 -0
  14. package/commands/release.mjs +77 -0
  15. package/commands/reminder.mjs +172 -0
  16. package/commands/setup.mjs +508 -0
  17. package/commands/skill.mjs +91 -0
  18. package/commands/tui.mjs +50 -0
  19. package/commands/update.mjs +161 -0
  20. package/docs/advanced.md +334 -0
  21. package/docs/mcp-setup.md +368 -0
  22. package/docs/operations-guide.md +587 -0
  23. package/docs/recipes.md +259 -0
  24. package/docs/security.md +151 -0
  25. package/examples/mcp/antigravity.mcp_config.json +8 -0
  26. package/examples/mcp/codex.config.toml +5 -0
  27. package/examples/mcp/copilot.mcp.json +9 -0
  28. package/lib/agent-skill.mjs +16 -0
  29. package/lib/api-auth.mjs +1259 -0
  30. package/lib/api.mjs +1422 -0
  31. package/lib/apply-ledger.mjs +227 -0
  32. package/lib/atomic-file.mjs +24 -0
  33. package/lib/auth-diagnostics.mjs +113 -0
  34. package/lib/auth-errors.mjs +22 -0
  35. package/lib/auth-redaction.mjs +78 -0
  36. package/lib/auth-terminal.mjs +97 -0
  37. package/lib/auth.mjs +323 -0
  38. package/lib/batch-parser.mjs +145 -0
  39. package/lib/batch-workflow.mjs +842 -0
  40. package/lib/commit-workflow.mjs +402 -0
  41. package/lib/config.mjs +191 -0
  42. package/lib/credential-store.mjs +130 -0
  43. package/lib/diagnostics.mjs +307 -0
  44. package/lib/entrypoint.mjs +14 -0
  45. package/lib/file-lock.mjs +44 -0
  46. package/lib/http.mjs +125 -0
  47. package/lib/jira-api.mjs +258 -0
  48. package/lib/jira-auth.mjs +203 -0
  49. package/lib/jira-workflow.mjs +523 -0
  50. package/lib/keychain.mjs +105 -0
  51. package/lib/legacy-migration.mjs +66 -0
  52. package/lib/list-navigation.mjs +19 -0
  53. package/lib/logwork-config.mjs +199 -0
  54. package/lib/logwork-f03-enrich.mjs +41 -0
  55. package/lib/macos.mjs +33 -0
  56. package/lib/manual-apply-state.mjs +35 -0
  57. package/lib/manual-commands.mjs +294 -0
  58. package/lib/manual-drafts.mjs +154 -0
  59. package/lib/manual-ink-app.mjs +1654 -0
  60. package/lib/manual-ink-auth.mjs +349 -0
  61. package/lib/manual-ink-ui.mjs +675 -0
  62. package/lib/manual-input.mjs +21 -0
  63. package/lib/manual-logwork-wizard.mjs +310 -0
  64. package/lib/manual-mcp.mjs +187 -0
  65. package/lib/manual-repl.mjs +1037 -0
  66. package/lib/manual-targets.mjs +78 -0
  67. package/lib/mcp-server.mjs +833 -0
  68. package/lib/os-notification.mjs +105 -0
  69. package/lib/package-info.mjs +17 -0
  70. package/lib/paths.mjs +68 -0
  71. package/lib/project-identity.mjs +66 -0
  72. package/lib/project-mapping-workflow.mjs +309 -0
  73. package/lib/project-resolver.mjs +373 -0
  74. package/lib/query-workflow.mjs +553 -0
  75. package/lib/reconciliation-workflow.mjs +446 -0
  76. package/lib/release-doctor.mjs +448 -0
  77. package/lib/reminder-config.mjs +71 -0
  78. package/lib/reminder-scheduler.mjs +301 -0
  79. package/lib/reminder-service.mjs +118 -0
  80. package/lib/reminder-state.mjs +38 -0
  81. package/lib/reminder-workflow.mjs +299 -0
  82. package/lib/ro-delete-args.mjs +38 -0
  83. package/lib/ro-delete-workflow.mjs +115 -0
  84. package/lib/ro-edit-args.mjs +142 -0
  85. package/lib/ro-edit-workflow.mjs +632 -0
  86. package/lib/ro-entry-reader.mjs +56 -0
  87. package/lib/ro-resubmit-workflow.mjs +134 -0
  88. package/lib/terminal-auth-prompts.mjs +120 -0
  89. package/lib/ui.mjs +133 -0
  90. package/lib/update-service.mjs +350 -0
  91. package/lib/util.mjs +66 -0
  92. package/lib/windows-credential-manager.mjs +260 -0
  93. package/lib/worklog-task-resolver.mjs +113 -0
  94. package/package.json +73 -4
  95. package/setup.sh +22 -0
  96. package/skills/logwork/SKILL.md +43 -0
@@ -0,0 +1,161 @@
1
+ import { confirm, isCancel } from '@clack/prompts';
2
+ import {
3
+ checkForUpdates,
4
+ installUpdate,
5
+ parseSemver
6
+ } from '../lib/update-service.mjs';
7
+
8
+ export function parseUpdateArgs(argv) {
9
+ const args = [...argv];
10
+ let command = 'check';
11
+ let force = false;
12
+ let json = false;
13
+ let yes = false;
14
+ let version;
15
+ let help = false;
16
+
17
+ if (args[0] && !args[0].startsWith('-')) {
18
+ command = args.shift();
19
+ }
20
+ if (!['check', 'install'].includes(command)) {
21
+ throw new Error(`Unknown update command: ${command}. Use check or install.`);
22
+ }
23
+
24
+ for (let index = 0; index < args.length; index += 1) {
25
+ const arg = args[index];
26
+ if (arg === '--help' || arg === '-h') {
27
+ help = true;
28
+ continue;
29
+ }
30
+ if (arg === '--json') {
31
+ json = true;
32
+ continue;
33
+ }
34
+ if (arg === '--force') {
35
+ force = true;
36
+ continue;
37
+ }
38
+ if (arg === '--yes' || arg === '-y') {
39
+ yes = true;
40
+ continue;
41
+ }
42
+ if (arg === '--version') {
43
+ version = args[index + 1];
44
+ if (!version) {
45
+ throw new Error('--version requires an exact SemVer value.');
46
+ }
47
+ index += 1;
48
+ continue;
49
+ }
50
+ if (arg.startsWith('--version=')) {
51
+ version = arg.slice('--version='.length);
52
+ continue;
53
+ }
54
+ throw new Error(`Unknown update option: ${arg}`);
55
+ }
56
+
57
+ if (command === 'check' && (yes || version)) {
58
+ throw new Error('--yes and --version are only valid with update install.');
59
+ }
60
+ if (command === 'install' && force) {
61
+ throw new Error('--force is only valid with update check; install always checks npm again.');
62
+ }
63
+ if (version && !parseSemver(version)) {
64
+ throw new Error('--version must be an exact SemVer value such as 1.2.3.');
65
+ }
66
+
67
+ return { command, force, json, yes, version, help };
68
+ }
69
+
70
+ export async function runUpdateCli(argv, {
71
+ checkForUpdatesFn = checkForUpdates,
72
+ installUpdateFn = installUpdate,
73
+ promptConfirm = defaultConfirm,
74
+ isTTY = Boolean(process.stdin.isTTY && process.stdout.isTTY),
75
+ output = process.stdout
76
+ } = {}) {
77
+ const options = parseUpdateArgs(argv);
78
+ if (options.help) {
79
+ output.write(`${formatUpdateHelp()}\n`);
80
+ return 0;
81
+ }
82
+
83
+ if (options.command === 'check') {
84
+ const result = await checkForUpdatesFn({ force: options.force });
85
+ printResult(output, result, options.json);
86
+ return 0;
87
+ }
88
+
89
+ const latest = await checkForUpdatesFn({
90
+ force: true,
91
+ allowStaleOnError: false
92
+ });
93
+ const targetVersion = options.version || latest.latestVersion;
94
+ if (targetVersion !== latest.latestVersion) {
95
+ throw new Error(`Only the npm latest version can be installed. Requested ${targetVersion}; latest is ${latest.latestVersion}.`);
96
+ }
97
+ if (!latest.updateAvailable) {
98
+ printResult(output, latest, options.json);
99
+ return 0;
100
+ }
101
+
102
+ let approved = options.yes;
103
+ if (!approved) {
104
+ if (!isTTY) {
105
+ throw new Error('Interactive confirmation is unavailable. Re-run with --yes to install the update.');
106
+ }
107
+ approved = await promptConfirm(`Install Logwork Helper ${targetVersion}?`);
108
+ }
109
+ if (!approved) {
110
+ output.write('Update cancelled.\n');
111
+ return 0;
112
+ }
113
+
114
+ const result = await installUpdateFn({
115
+ version: targetVersion,
116
+ confirm: true,
117
+ stdio: options.json ? 'pipe' : 'inherit'
118
+ });
119
+ printResult(output, result, options.json);
120
+ return 0;
121
+ }
122
+
123
+ export function formatUpdateHelp() {
124
+ return `Usage:
125
+ logwork update check [--force] [--json]
126
+ logwork update install [--version <semver>] [--yes] [--json]
127
+
128
+ Commands:
129
+ check Compare the installed version with npm latest. Results are cached for 24 hours.
130
+ install Re-check npm latest, install that exact version, and verify the local runtime.
131
+
132
+ Options:
133
+ --force Ignore the update cache when checking
134
+ --version <semver> Install only when this exact version is npm latest
135
+ -y, --yes Skip the interactive install confirmation
136
+ --json Print structured JSON output
137
+ -h, --help Show this help`;
138
+ }
139
+
140
+ async function defaultConfirm(message) {
141
+ const result = await confirm({
142
+ message,
143
+ initialValue: false
144
+ });
145
+ return !isCancel(result) && result === true;
146
+ }
147
+
148
+ function printResult(output, result, json) {
149
+ if (json) {
150
+ output.write(`${JSON.stringify(result, null, 2)}\n`);
151
+ return;
152
+ }
153
+ output.write(`${result.summary}\n`);
154
+ if (result.updateAvailable) {
155
+ output.write(`Release: ${result.releaseUrl}\n`);
156
+ output.write('Install: logwork update install\n');
157
+ }
158
+ if (result.warning) {
159
+ output.write(`Warning: ${result.warning}\n`);
160
+ }
161
+ }
@@ -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
+ ```