logwork-cli 1.1.1 → 1.3.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/README.md +53 -25
- package/RELEASE.md +4 -2
- package/bin/logwork.mjs +2 -2
- package/commands/commits.mjs +128 -13
- package/commands/history.mjs +0 -4
- package/commands/mcp.mjs +266 -0
- package/commands/quick.mjs +38 -23
- package/commands/reminder.mjs +41 -2
- package/commands/setup.mjs +197 -42
- package/commands/tui.mjs +1 -0
- package/docs/advanced.md +18 -7
- package/docs/mcp-setup.md +120 -26
- package/docs/operations-guide.md +50 -2
- package/docs/recipes.md +40 -0
- package/docs/security.md +23 -2
- package/examples/mcp/antigravity.mcp_config.json +2 -2
- package/examples/mcp/codex.config.toml +2 -2
- package/examples/mcp/copilot.mcp.json +2 -2
- package/lib/api-auth-forms.mjs +393 -0
- package/lib/api-auth-http.mjs +184 -0
- package/lib/api-auth-support.mjs +101 -0
- package/lib/api-auth-tokens.mjs +129 -0
- package/lib/api-auth.mjs +39 -813
- package/lib/api.mjs +38 -1422
- package/lib/apply-ledger.mjs +1 -1
- package/lib/batch-workflow.mjs +187 -2
- package/lib/commit-workflow.mjs +345 -23
- package/lib/config.mjs +7 -0
- package/lib/diagnostics.mjs +116 -4
- package/lib/jira-api.mjs +25 -3
- package/lib/jira-workflow.mjs +36 -6
- package/lib/launcher.mjs +303 -0
- package/lib/logwork-config.mjs +64 -13
- package/lib/manual-apply-state.mjs +15 -0
- package/lib/manual-commands.mjs +2 -2
- package/lib/manual-ink-app.mjs +142 -1282
- package/lib/manual-ink-draft-actions.mjs +227 -0
- package/lib/manual-ink-interaction.mjs +318 -0
- package/lib/manual-ink-session.mjs +41 -0
- package/lib/manual-ink-task-editor.mjs +338 -0
- package/lib/manual-ink-ui.mjs +38 -0
- package/lib/manual-ink-wizard.mjs +520 -0
- package/lib/manual-mcp.mjs +78 -20
- package/lib/manual-repl.mjs +171 -22
- package/lib/mcp-install.mjs +930 -0
- package/lib/mcp-server.mjs +51 -20
- package/lib/node-runtime.mjs +155 -0
- package/lib/paths.mjs +7 -0
- package/lib/project-mapping-workflow.mjs +32 -27
- package/lib/query-workflow.mjs +19 -1
- package/lib/reconciliation-workflow.mjs +1 -1
- package/lib/reminder-config.mjs +38 -2
- package/lib/reminder-scheduler.mjs +85 -18
- package/lib/reminder-service.mjs +42 -3
- package/lib/reminder-workflow.mjs +118 -22
- package/lib/repo-project-suggestions.mjs +285 -0
- package/lib/ro-api-diagnostics.mjs +109 -0
- package/lib/ro-api-entries.mjs +359 -0
- package/lib/ro-api-fields.mjs +290 -0
- package/lib/ro-api-http.mjs +68 -0
- package/lib/ro-api-projects.mjs +137 -0
- package/lib/ro-api-tasks.mjs +50 -0
- package/lib/ro-api-timesheet.mjs +413 -0
- package/lib/ro-delete-workflow.mjs +2 -1
- package/lib/ro-entry-reader.mjs +11 -6
- package/lib/ro-resubmit-workflow.mjs +2 -1
- package/lib/terminal-auth-prompts.mjs +7 -4
- package/lib/ui.mjs +121 -56
- package/package.json +11 -4
- package/skills/logwork/SKILL.md +10 -4
package/docs/mcp-setup.md
CHANGED
|
@@ -1,75 +1,130 @@
|
|
|
1
1
|
# MCP Setup
|
|
2
2
|
|
|
3
|
-
`logwork setup`
|
|
3
|
+
Run `logwork setup` and answer yes for each client. That is the whole setup: you do not edit MCP JSON or TOML yourself, and you do not need to know where Node is installed.
|
|
4
4
|
|
|
5
5
|
For the full RO/Jira/Both processing model, mapping, reconciliation, history, reminders and updates, see the [operations guide](operations-guide.md).
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Automatic Setup
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
`logwork setup` (and `logwork mcp install` at any time later) looks for these clients and adds or updates the `logwork` server in each one it finds. A client counts as found only when its config directory or CLI exists; setup never creates config for a client you do not have.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
| Client | Detected by | What is changed |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| Claude Code | `claude` on `PATH`, or `~/.claude.json` | `claude mcp remove --scope user logwork`, then `claude mcp add --scope user logwork -- <command> <args>`. Without the CLI: the top-level `mcpServers` in `~/.claude.json`. |
|
|
14
|
+
| Cursor | `~/.cursor` | `mcpServers.logwork` in `~/.cursor/mcp.json` |
|
|
15
|
+
| Codex | `~/.codex` | the `[mcp_servers.logwork]` table in `~/.codex/config.toml` |
|
|
16
|
+
| VS Code (user) | `~/Library/Application Support/Code/User` (macOS), `%APPDATA%\Code\User` (Windows) | `servers.logwork` (`"type": "stdio"`) in `mcp.json` there |
|
|
17
|
+
| Google Antigravity | `~/.gemini/antigravity` | `mcpServers.logwork` in `~/.gemini/antigravity/mcp_config.json` |
|
|
18
|
+
|
|
19
|
+
How files are edited:
|
|
20
|
+
- Each file is read, parsed and merged. Only the `logwork` entry changes; other servers and settings stay as they are. Extra fields you added to the `logwork` entry (such as `env`) are kept, except in Codex, where the whole `[mcp_servers.logwork]` table (with sub-tables such as `[mcp_servers.logwork.env]`) is replaced.
|
|
21
|
+
- An old `logwork-helper` entry is removed. In Claude Code, a stale project-scope (`--scope local`) `logwork` entry is removed too, because it would hide the user-scope one.
|
|
22
|
+
- Before the first change, the file is copied to `<file>.logwork-backup-<YYYYMMDDHHmmss>` next to it. Then the new file is written atomically. A symlinked config is written through the link.
|
|
23
|
+
- When the entry is already current, nothing is written and no backup is made.
|
|
24
|
+
- When a file does not parse cleanly (JSON with comments or trailing commas, TOML with an unusual layout such as an inline `mcp_servers` table), it is not touched. The result says "could not update automatically" and shows the snippet to paste.
|
|
25
|
+
|
|
26
|
+
Commands:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
logwork mcp status # per client: current, stale (and why), missing, leftover logwork-helper
|
|
30
|
+
logwork mcp install # asks once per client that needs a change (default: yes)
|
|
31
|
+
logwork mcp install --client cursor # only some clients (repeatable: claude, cursor, codex, vscode, antigravity)
|
|
32
|
+
logwork mcp install --dry-run # show the planned changes, write nothing
|
|
33
|
+
logwork mcp install --yes # no questions
|
|
34
|
+
logwork setup --yes # setup, updating every detected client without asking
|
|
35
|
+
logwork setup --no-mcp-install # setup without touching MCP configs
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
When setup does not run in a terminal (for example from `logwork update`), it only prints what `logwork mcp install` would change.
|
|
39
|
+
|
|
40
|
+
`logwork doctor` includes the same per-client check.
|
|
41
|
+
|
|
42
|
+
## What The Configs Run
|
|
43
|
+
|
|
44
|
+
Every client runs one command under the server name `logwork`. The command never names a Node version, so `nvm install`, `brew upgrade node` or a new Node installer do not break it:
|
|
45
|
+
|
|
46
|
+
- **macOS:** `~/.logwork-cli/bin/logwork-launch mcp`. `logwork setup` writes this small `sh` script. It starts `~/.logwork-cli/bin/logwork.mjs` with the first Node 22+ it finds, in this order:
|
|
47
|
+
1. the Node that ran `logwork setup`;
|
|
48
|
+
2. `node` on `PATH`;
|
|
49
|
+
3. the newest nvm Node (`$NVM_DIR` or `~/.nvm`);
|
|
50
|
+
4. Volta (`~/.volta/bin/node`) and the fnm default;
|
|
51
|
+
5. `/opt/homebrew/bin/node`, `/usr/local/bin/node`.
|
|
52
|
+
|
|
53
|
+
If none is found, it prints one line ("install Node.js 22 or newer, or run `logwork setup` again") and exits with code 127.
|
|
54
|
+
- **Windows:** `<node.exe> %USERPROFILE%\.logwork-cli\bin\logwork.mjs mcp`. GUI clients would need `cmd /c` to run a `.cmd` launcher, so the config uses a stable `node.exe` instead:
|
|
55
|
+
- when Node runs from an nvm-windows version folder and `NVM_SYMLINK` is set, `%NVM_SYMLINK%\node.exe`, which follows `nvm use`;
|
|
56
|
+
- otherwise the Node that ran setup, usually `C:\Program Files\nodejs\node.exe`, which an installer upgrade keeps.
|
|
57
|
+
|
|
58
|
+
With any other Node location (Scoop, a portable zip), re-run `logwork setup` after moving or upgrading Node.
|
|
59
|
+
|
|
60
|
+
The paths are absolute because GUI IDEs (started from the Dock, Finder or Start menu) often do not get your shell's `PATH`, so a bare `node` or `logwork` would not be found.
|
|
12
61
|
|
|
13
|
-
##
|
|
62
|
+
## Manual Setup (Fallback)
|
|
14
63
|
|
|
15
|
-
|
|
64
|
+
Use this only for a client that `logwork setup` does not support, or one whose file it could not update. `logwork setup` prints the snippet for each client it could not update. You can also open the terminal UI with `logwork` and type `/mcp`, or `/mcp <client>` for a single client; both print your real paths.
|
|
65
|
+
|
|
66
|
+
The examples use `/Users/<user>` as a placeholder. On Windows, use the paths printed by `logwork setup` or `/mcp`, for example `"command": "C:\\Program Files\\nodejs\\node.exe"` and `"args": ["C:\\Users\\<user>\\.logwork-cli\\bin\\logwork.mjs", "mcp"]` inside JSON or TOML strings.
|
|
67
|
+
|
|
68
|
+
### Cursor / Google Antigravity
|
|
69
|
+
|
|
70
|
+
`~/.cursor/mcp.json`, or `~/.gemini/antigravity/mcp_config.json`:
|
|
16
71
|
|
|
17
72
|
```json
|
|
18
73
|
{
|
|
19
74
|
"mcpServers": {
|
|
20
75
|
"logwork": {
|
|
21
|
-
"command": "
|
|
22
|
-
"args": ["
|
|
76
|
+
"command": "/Users/<user>/.logwork-cli/bin/logwork-launch",
|
|
77
|
+
"args": ["mcp"]
|
|
23
78
|
}
|
|
24
79
|
}
|
|
25
80
|
}
|
|
26
81
|
```
|
|
27
82
|
|
|
28
|
-
|
|
83
|
+
### Codex
|
|
29
84
|
|
|
30
85
|
`~/.codex/config.toml`, or project `.codex/config.toml`:
|
|
31
86
|
|
|
32
87
|
```toml
|
|
33
88
|
[mcp_servers.logwork]
|
|
34
|
-
command = "
|
|
35
|
-
args = ["
|
|
89
|
+
command = "/Users/<user>/.logwork-cli/bin/logwork-launch"
|
|
90
|
+
args = ["mcp"]
|
|
36
91
|
startup_timeout_sec = 20
|
|
37
92
|
tool_timeout_sec = 120
|
|
38
93
|
```
|
|
39
94
|
|
|
40
|
-
|
|
95
|
+
### GitHub Copilot / VS Code
|
|
41
96
|
|
|
42
|
-
Workspace `.vscode/mcp.json`, or your VS Code user
|
|
97
|
+
Workspace `.vscode/mcp.json`, or your VS Code user `mcp.json`:
|
|
43
98
|
|
|
44
99
|
```json
|
|
45
100
|
{
|
|
46
101
|
"servers": {
|
|
47
102
|
"logwork": {
|
|
48
103
|
"type": "stdio",
|
|
49
|
-
"command": "
|
|
50
|
-
"args": ["
|
|
104
|
+
"command": "/Users/<user>/.logwork-cli/bin/logwork-launch",
|
|
105
|
+
"args": ["mcp"]
|
|
51
106
|
}
|
|
52
107
|
}
|
|
53
108
|
}
|
|
54
109
|
```
|
|
55
110
|
|
|
56
|
-
|
|
111
|
+
### Claude Code
|
|
57
112
|
|
|
58
113
|
```bash
|
|
59
|
-
claude mcp add --transport stdio logwork --
|
|
114
|
+
claude mcp add --transport stdio --scope user logwork -- ~/.logwork-cli/bin/logwork-launch mcp
|
|
60
115
|
```
|
|
61
116
|
|
|
62
117
|
From Windows PowerShell:
|
|
63
118
|
|
|
64
119
|
```powershell
|
|
65
|
-
claude mcp add --transport stdio logwork -- node 'C:\Users\<user>\.logwork-cli\bin\logwork.mjs' mcp
|
|
120
|
+
claude mcp add --transport stdio --scope user logwork -- 'C:\Program Files\nodejs\node.exe' 'C:\Users\<user>\.logwork-cli\bin\logwork.mjs' mcp
|
|
66
121
|
```
|
|
67
122
|
|
|
68
123
|
Or add the Cursor JSON above to the project `.mcp.json`.
|
|
69
124
|
|
|
70
|
-
Templates are also in [examples/mcp](../examples/mcp/)
|
|
125
|
+
Templates (macOS form) are also in [examples/mcp](../examples/mcp/); on Windows, use the paths printed by `/mcp`.
|
|
71
126
|
|
|
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.
|
|
127
|
+
If you used `logwork-helper` before and edit configs by hand, delete its old MCP entry. It points at `~/.logwork-helper/mcp-server.mjs`, which is the old runtime.
|
|
73
128
|
|
|
74
129
|
## Exposed Tools
|
|
75
130
|
|
|
@@ -89,18 +144,18 @@ Previews expire after 1 hour. They are also lost when the server restarts.
|
|
|
89
144
|
| Group | Tool | Kind | Purpose |
|
|
90
145
|
|---|---|---|---|
|
|
91
146
|
| Read | `get_logwork` | read-only | Booked vs logged RO hours by day and project, with entries (`logworkId`, worklog task, description, status). |
|
|
92
|
-
| Read | `draft_from_commits` | read-only | Your git commits (all branches, your author) for a period in the given `repos`, grouped per day into draft lines with a suggested worklog task and hours that fill
|
|
147
|
+
| Read | `draft_from_commits` | read-only | Your git commits (all branches, your author) for a period in the given `repos`, grouped per day into draft lines with a suggested worklog task, an RO project (repo mapping, else ticket/keyword mappings and bookings) and hours that fill each project's remaining booked time. Returns `draftText` and `projectOverrides` for `log_work`, `unmappedRepos`, and `repoSuggestions` (likely project per unmapped repo, with reasons) plus `projectCandidates`. |
|
|
93
148
|
| Read | `list_projects` | read-only | RO memberships (`projectMemberId`, `projectId`, `projectName`) and local mappings. |
|
|
94
149
|
| Read | `list_tasks` | read-only | RO worklog task catalog for one `projectId`: id, name, type of work, and when to use each task. |
|
|
95
150
|
| Read | `get_jira_issue` | read-only | Jira issue key, summary and status. |
|
|
96
151
|
| Read | `reconcile` | read-only | Compare RO and Jira hours by day. Never writes. |
|
|
97
152
|
| Read | `get_history` | read-only (local) | Local apply history. Contains no credentials. |
|
|
98
|
-
| RO write | `log_work` | two-call write | Create new RO entries from a weekly block (worklog task + description). |
|
|
153
|
+
| RO write | `log_work` | two-call write | Create new RO entries from a weekly block (worklog task + description). The preview flags possible duplicates of existing RO entries; apply refuses them without `allowDuplicates: true`. |
|
|
99
154
|
| 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. |
|
|
100
155
|
| RO write | `resubmit_entry` | two-call write | Fix and resubmit a rejected entry (hours, type, description, note to PM). |
|
|
101
156
|
| RO write | `delete_entry` | two-call, destructive | Delete a submitted or approved entry. |
|
|
102
157
|
| Jira write | `log_jira_work` | two-call write | Create Jira worklogs. The description becomes the worklog comment. |
|
|
103
|
-
| Config | `map_project` | local write, `confirm` | Map ticket prefixes or
|
|
158
|
+
| Config | `map_project` | local write, `confirm` | Map ticket prefixes, keywords or git repos (`repos`) to an RO project (`.logwork.json`). |
|
|
104
159
|
| Config | `reminder` | `action`: status / enable / disable / test | Native OS reminder. Every action except `status` needs `confirm: true`. |
|
|
105
160
|
| Config | `update` | `action`: check / install | npm self-update. `install` needs `confirm: true`. |
|
|
106
161
|
| Auth | `login` | local | `target: "ro"` (default) opens or explains a terminal login. `target: "jira"` explains how to save a PAT. Never accepts credentials. |
|
|
@@ -189,9 +244,18 @@ Expected flow:
|
|
|
189
244
|
|
|
190
245
|
1. `get_logwork` shows which days and projects still have booked hours to fill.
|
|
191
246
|
2. `draft_from_commits` (with `repos` set to the workspace folders) groups your commits into draft lines with hours.
|
|
247
|
+
- Each line gets a project. A `map_project` mapping whose `repos` holds the repo comes first; then ticket/keyword mappings and that day's booked projects.
|
|
248
|
+
- Each project's remaining hours are split across its own lines and never exceeded. Lines without a project share the room of booked projects that no line claimed.
|
|
249
|
+
- It returns `draftText`, plus `projectOverrides` (preview entry id → `projectMemberId`) for each line with a project.
|
|
250
|
+
- It also returns `unmappedRepos` (repo paths whose lines got no project), `repoSuggestions` and `projectCandidates`:
|
|
251
|
+
- `repoSuggestions` maps each unmapped repo to up to 5 projects, best first: `{ projectName, projectMemberId, projectId, score, reasons }`. The evidence is a ticket from the repo's commits that you logged to the project in the last 30 days, the repo folder or git remote name matching the project name (its acronym in parentheses or its initials), and the only project booked on the repo's commit days. `reasons` are readable, for example `ticket FCS-12 was logged to this project on 2026-11-03` or `repo name matches FCS`.
|
|
252
|
+
- `projectCandidates` lists every member project (booked ones first).
|
|
253
|
+
- The assistant asks one short question per repo by project name ("Is fcs-web part of GKE Fair Chem System (FCS)?"). On a yes it calls `map_project` with `projectName` (or the suggestion's `projectMemberId`), `repos` and `confirm: true`, then runs `draft_from_commits` again.
|
|
192
254
|
3. `list_tasks` confirms the worklog task names for each project.
|
|
193
255
|
4. The assistant rewrites vague descriptions, shows you the block and waits for approval.
|
|
194
|
-
5. `log_work(text)` previews the entries, then `log_work(batchId, confirm: true)` applies them.
|
|
256
|
+
5. `log_work(text, projectOverrides)` previews the entries, then `log_work(batchId, confirm: true)` applies them.
|
|
257
|
+
- Preview entry ids are `<date>-<NN>`, where NN counts entry lines through the whole text. The overrides match `draftText` as returned.
|
|
258
|
+
- If lines are added, removed or reordered, the assistant renumbers the overrides.
|
|
195
259
|
|
|
196
260
|
|
|
197
261
|
|
|
@@ -227,7 +291,9 @@ A suggestion is not an approved write. It still goes through the two-call write
|
|
|
227
291
|
2. Call `list_projects`, then `list_tasks` with the `projectId`, to pick valid worklog task names.
|
|
228
292
|
3. Call `log_work` with `text`.
|
|
229
293
|
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.
|
|
230
|
-
5. Call `log_work` with `batchId` and `confirm: true`.
|
|
294
|
+
5. Call `log_work` with `batchId` and `confirm: true`.
|
|
295
|
+
- Add `allowUnbooked: true` only if the user agreed to log to a project that is not booked on that date.
|
|
296
|
+
- Add `allowDuplicates: true` only if the user confirmed that lines flagged as possible duplicates are new work (see below).
|
|
231
297
|
|
|
232
298
|
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`.
|
|
233
299
|
|
|
@@ -338,6 +404,13 @@ The two applies are intentionally not atomic. `log_work` never writes Jira, and
|
|
|
338
404
|
|
|
339
405
|
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`.
|
|
340
406
|
|
|
407
|
+
For commit drafts, a mapping can also list git repos.
|
|
408
|
+
- When `draft_from_commits` reports `unmappedRepos`, the assistant confirms the top `repoSuggestions` entry with you by name, then calls `map_project` with `projectName`, `repos` (absolute paths) and `confirm: true`.
|
|
409
|
+
- At least one ticket prefix or repo is required.
|
|
410
|
+
- A subfolder is stored as the root of its repo.
|
|
411
|
+
- Paths are compared without trailing separators, and case-insensitively on Windows.
|
|
412
|
+
- In a terminal, `logwork commits` asks for each unmapped repo with a picker (likely project first). In the terminal UI, `/map --repo [path]` opens the same picker and `/map --repo [path] <project name>` maps by name. The path defaults to the current folder.
|
|
413
|
+
|
|
341
414
|
Mappings are stored in one of two places:
|
|
342
415
|
- **User scope (default):** `~/.logwork-cli/.logwork.json`.
|
|
343
416
|
- **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.
|
|
@@ -349,7 +422,8 @@ Mappings are stored in one of two places:
|
|
|
349
422
|
"projectName": "2621A-SIT-HTML BUILDER-PRJ",
|
|
350
423
|
"projectMemberId": 5234,
|
|
351
424
|
"tickets": ["SCB"],
|
|
352
|
-
"keywords": ["question bank", "programme", "cluster"]
|
|
425
|
+
"keywords": ["question bank", "programme", "cluster"],
|
|
426
|
+
"repos": ["/Users/me/code/html-builder"]
|
|
353
427
|
}
|
|
354
428
|
]
|
|
355
429
|
}
|
|
@@ -366,3 +440,23 @@ Only allow this when the matched project is correct. Apply with:
|
|
|
366
440
|
```json
|
|
367
441
|
{ "batchId": "<from preview>", "confirm": true, "allowUnbooked": true }
|
|
368
442
|
```
|
|
443
|
+
|
|
444
|
+
### Possible Duplicates
|
|
445
|
+
|
|
446
|
+
Before showing a `log_work` preview, the server reads your RO entries for each date in the batch (`GET /logwork/day`).
|
|
447
|
+
|
|
448
|
+
An entry is flagged `possibleDuplicate` in two cases:
|
|
449
|
+
- **It matches an existing RO entry** on the same date: the same worklog task (by id, or by name when RO has no id), the same hours and the same description. The description compare ignores extra spaces and letter case.
|
|
450
|
+
- **It repeats an earlier line** of the same batch.
|
|
451
|
+
|
|
452
|
+
The summary shows a `WARNING possible duplicate` line for each one.
|
|
453
|
+
|
|
454
|
+
Apply refuses the whole batch while duplicates remain, and nothing is written. The preview stays cached, so after the user confirms the lines are really new work, call again with the same `batchId`:
|
|
455
|
+
|
|
456
|
+
```json
|
|
457
|
+
{ "batchId": "<from preview>", "confirm": true, "allowDuplicates": true }
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
Usually the better fix is to drop the duplicated lines and preview again.
|
|
461
|
+
|
|
462
|
+
If RO cannot be read for a date (other than a login problem), the preview is not blocked. Its summary notes that the duplicate check was skipped for that date. In the terminal UI, `/apply` asks a separate question before submitting possible duplicates; the default answer is no.
|
package/docs/operations-guide.md
CHANGED
|
@@ -19,6 +19,8 @@ npm install -g logwork-cli
|
|
|
19
19
|
logwork setup
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
+
`logwork setup` also writes the launcher (`~/.logwork-cli/bin/logwork-launch` on macOS) and adds the `logwork` MCP server to the clients it finds (Claude Code, Cursor, Codex, VS Code, Google Antigravity), asking once per client. Each edited config is backed up first. Options: `--yes` (no questions), `--no-mcp-install` (do not touch MCP configs). Check or redo it later with `logwork mcp status` and `logwork mcp install`; see [MCP setup](mcp-setup.md#automatic-setup).
|
|
23
|
+
|
|
22
24
|
Upgrading from `logwork-helper`: run `npm uninstall -g logwork-helper` first. Both packages provide a `logwork` command, and npm refuses to overwrite it (`EEXIST`). If `~/.logwork-helper` was already deleted, the uninstall leaves broken links behind; remove them with `P="$(npm prefix -g)"; rm -f "$P/bin/logwork" "$P"/bin/logwork-helper* "$P/lib/node_modules/logwork-helper"`, or run `npx logwork-cli@latest setup`, which removes them.
|
|
23
25
|
|
|
24
26
|
Authenticate each target from Terminal:
|
|
@@ -49,7 +51,7 @@ Resource Optimiser credentials and Jira PATs are never accepted by MCP tools. Th
|
|
|
49
51
|
| Delete RO entry | `logwork delete` | - | `delete_entry` | Apply call only |
|
|
50
52
|
| Log Jira | - | `/logwork jira` | `log_jira_work` | Apply call only |
|
|
51
53
|
| Log Both | - | `/logwork both` | `log_work` + `log_jira_work` separately | Apply calls only |
|
|
52
|
-
| Project mapping | - | `/projects`, `/map` | `list_projects`, `map_project` | Local config only |
|
|
54
|
+
| Project mapping | - | `/projects`, `/map`, `/map --repo` | `list_projects`, `map_project` | Local config only |
|
|
53
55
|
| RO worklog task catalog | - | - | `list_tasks` | No |
|
|
54
56
|
| Reconcile RO/Jira | `logwork reconcile` | `/reconcile` | `reconcile` | No |
|
|
55
57
|
| Apply history | `logwork history` | `/history` | `get_history` | No |
|
|
@@ -188,6 +190,8 @@ MCP uses:
|
|
|
188
190
|
|
|
189
191
|
Every entry must contain exactly one Jira issue key. RO is not written by this flow.
|
|
190
192
|
|
|
193
|
+
In dry run (`LOGWORK_DRY_RUN=1`), the Jira apply still reads Jira for the duplicate check but sends no worklog. It returns `status: "dry_run"` with the request each entry would send, and the summary starts with `DRY RUN`. Apply history records it as `dry_run`, not as submitted.
|
|
194
|
+
|
|
191
195
|
### Both
|
|
192
196
|
|
|
193
197
|
Use the combined terminal flow when the same date/tasks should be sent to both systems:
|
|
@@ -271,6 +275,8 @@ Submitted 2 entries, 3h total.
|
|
|
271
275
|
|
|
272
276
|
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.
|
|
273
277
|
|
|
278
|
+
Preview also reads the RO entries of each date. An entry with the same worklog task, hours and description as an existing entry (or an earlier line of the batch) gets a `WARNING possible duplicate` line. Applying it requires a separate decision: `allowDuplicates: true`, or a yes to the duplicate question in the terminal UI. Without it, nothing is written. If the day cannot be read, the preview notes that the duplicate check was skipped and does not block.
|
|
279
|
+
|
|
274
280
|
## Jira Processing Example
|
|
275
281
|
|
|
276
282
|
For each entry, Jira preview:
|
|
@@ -344,6 +350,14 @@ RO project mapping can use:
|
|
|
344
350
|
- Task keywords, for example `maintenance mode`.
|
|
345
351
|
- Explicit project selection during preview.
|
|
346
352
|
- Jira project key/name metadata in the terminal Both flow to rank RO memberships.
|
|
353
|
+
- Git repo roots (`repos`), for commit drafts.
|
|
354
|
+
|
|
355
|
+
A repo with no mapping is mapped once, in place, without ids:
|
|
356
|
+
- `logwork commits` in an interactive terminal asks `Which RO project does <repo> belong to?` with the likely project preselected, saves the choice and redoes the draft (`--no-prompt` turns this off).
|
|
357
|
+
- In the terminal UI, `/map --repo [path]` opens the same picker; `/map --repo [path] <project name>` maps by name (case-insensitive, then a unique part of the name; an ambiguous name opens the picker).
|
|
358
|
+
- MCP: `draft_from_commits` returns `repoSuggestions` per unmapped repo; the assistant confirms the top one by name and calls `map_project` with `projectName` and `repos`.
|
|
359
|
+
|
|
360
|
+
The likely project comes from ticket keys in the repo's commits that you logged to a project in the last 30 days, then the repo folder or git remote name against the project name (acronym in parentheses, initials, shared words), then the only project booked on the repo's commit days.
|
|
347
361
|
|
|
348
362
|
Example MCP sequence:
|
|
349
363
|
|
|
@@ -433,6 +447,8 @@ Other operations:
|
|
|
433
447
|
|
|
434
448
|
```bash
|
|
435
449
|
logwork reminder enable --time 18:00 --target ro
|
|
450
|
+
logwork reminder enable --repo ~/code/app --repo ~/code/api
|
|
451
|
+
logwork reminder enable --no-repos
|
|
436
452
|
logwork reminder status
|
|
437
453
|
logwork reminder test
|
|
438
454
|
logwork reminder disable
|
|
@@ -447,9 +463,21 @@ Behavior:
|
|
|
447
463
|
- Missing auth produces an actionable notification without exposing API details.
|
|
448
464
|
- macOS uses a user `launchd` agent (`sg.vinova.logwork-cli.reminder`).
|
|
449
465
|
- Windows uses an interactive user Task Scheduler task (`Logwork Reminder`).
|
|
450
|
-
- The scheduler runs
|
|
466
|
+
- The scheduler runs the same command as the MCP configs with `reminder run --home ~/.logwork-cli`:
|
|
467
|
+
- macOS: `~/.logwork-cli/bin/logwork-launch`, which finds a Node 22+ itself, so a Node upgrade does not break the reminder;
|
|
468
|
+
- Windows: a stable `node.exe` (the nvm-windows symlink, or `C:\Program Files\nodejs\node.exe`) plus `~/.logwork-cli/bin/logwork.mjs`.
|
|
469
|
+
- `logwork reminder status` and `logwork doctor` warn when the scheduled command is missing, when the launcher finds no usable Node, and when a schedule from an older version still runs a raw Node path. Run `logwork setup` (or `logwork reminder enable`) to re-register it.
|
|
451
470
|
- Enabling or disabling the reminder also removes a leftover `logwork-helper` schedule.
|
|
452
471
|
|
|
472
|
+
Commit evidence:
|
|
473
|
+
|
|
474
|
+
- `--repo <path>` (repeatable) saves git repos in `reminder.json` as absolute paths. MCP: `reminder` with `action: "enable"` and `repos`. `--repo` or `repos` replaces the saved list, `--no-repos` or `repos: []` clears it, and leaving them out keeps it.
|
|
475
|
+
- Repos listed in a project mapping's `repos` field are added.
|
|
476
|
+
- When RO hours are missing, the reminder reads your commits today in those repos (read-only, the same reader as `logwork commits`, without another RO query) and adds `Hôm nay: <n> commit trong <k> repo`. The action line then points to `logwork commits today`.
|
|
477
|
+
- Run outside a git repo, `logwork commits today` falls back to the reminder repos.
|
|
478
|
+
- With no repos, no commits today, or any error reading them (missing repo, git not on the scheduler's `PATH`, a 20-second timeout), the plain message is shown.
|
|
479
|
+
- The notification stays a plain OS notification on both platforms (macOS `display notification`, a Windows toast). It has no buttons; open a terminal and run the command shown.
|
|
480
|
+
|
|
453
481
|
Example Both notification:
|
|
454
482
|
|
|
455
483
|
```text
|
|
@@ -460,6 +488,19 @@ Jira: chưa có worklog hôm nay
|
|
|
460
488
|
Mở Terminal và chạy: logwork
|
|
461
489
|
```
|
|
462
490
|
|
|
491
|
+
With reminder repos and commits today:
|
|
492
|
+
|
|
493
|
+
```text
|
|
494
|
+
Logwork hôm nay chưa hoàn tất
|
|
495
|
+
RO: 4/8h, còn thiếu 4h
|
|
496
|
+
Jira: chưa có worklog hôm nay
|
|
497
|
+
Hôm nay: 5 commit trong 2 repo
|
|
498
|
+
|
|
499
|
+
Mở Terminal và chạy: logwork commits today (bản nháp từ commit)
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
`logwork reminder test` sends a sample in this format.
|
|
503
|
+
|
|
463
504
|
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.
|
|
464
505
|
|
|
465
506
|
## End-User Updates
|
|
@@ -537,6 +578,9 @@ The release doctor checks package version consistency, self-dependencies, clean/
|
|
|
537
578
|
| Apply history | `.logwork-cli/apply-ledger.json` | No |
|
|
538
579
|
| Update cache | `.logwork-cli/update-state.json` | No |
|
|
539
580
|
| Reminder config/state | `.logwork-cli/reminder.json`, `.logwork-cli/reminder-state.json` | No |
|
|
581
|
+
| Runtime Node record | `.logwork-cli/runtime.json` (Node path and version from `logwork setup`) | No |
|
|
582
|
+
| Launcher (macOS) | `.logwork-cli/bin/logwork-launch`, written by `logwork setup` | No |
|
|
583
|
+
| MCP config backups | `<client config>.logwork-backup-<timestamp>`, next to each edited client config | No |
|
|
540
584
|
| RO/Jira sessions | OS credential store, service `logwork-cli` | Yes |
|
|
541
585
|
|
|
542
586
|
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.
|
|
@@ -551,7 +595,9 @@ Migration from `logwork-helper` happens on the first run, unless `LOGWORK_HOME`
|
|
|
551
595
|
Run the cross-platform suite:
|
|
552
596
|
|
|
553
597
|
```bash
|
|
598
|
+
npm run lint
|
|
554
599
|
npm test
|
|
600
|
+
npm run test:coverage # same suite with coverage thresholds; CI runs it on macOS
|
|
555
601
|
git diff --check
|
|
556
602
|
npm pack --dry-run
|
|
557
603
|
```
|
|
@@ -584,6 +630,8 @@ Recommended end-user checks after installation:
|
|
|
584
630
|
- Partial Both result: inspect `/history both`, then preview only the missing target.
|
|
585
631
|
- npm `E401`: refresh npm login with `npm login --registry=https://registry.npmjs.org/`.
|
|
586
632
|
- Reminder config/scheduler mismatch: rerun `reminder enable` or `reminder disable`.
|
|
633
|
+
- MCP client or reminder does not start after a Node change: run `logwork doctor` or `logwork mcp status`. `logwork setup` rewrites the launcher, re-registers the reminder and updates the MCP configs it can edit; paste the printed snippet only for a client it reports as "could not update automatically".
|
|
634
|
+
- `logwork mcp install` reports "could not update automatically": the file has comments, trailing commas or an unusual TOML layout. Paste the printed snippet by hand, or remove the comments and run it again.
|
|
587
635
|
- MCP after update: restart or reload the MCP connection.
|
|
588
636
|
|
|
589
637
|
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).
|
package/docs/recipes.md
CHANGED
|
@@ -39,6 +39,40 @@ List the Resource Optimiser worklog tasks for my booked project today, then log
|
|
|
39
39
|
|
|
40
40
|
The assistant uses `list_projects` and `list_tasks`, writes `+2 <task> | <description>`, and previews. If you write lines without `|`, the assistant can pass `defaultWorklogTask` (for example `Feature Development`) so each line becomes the description.
|
|
41
41
|
|
|
42
|
+
## Log From Commits Into The Right Projects
|
|
43
|
+
|
|
44
|
+
Each repo needs its RO project once. Just run the draft:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
logwork commits yesterday
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
For a repo with no project yet, it asks in place:
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
Which RO project does portal-web belong to?
|
|
54
|
+
› Customer Portal · ticket CP-12 was logged to this project on 2026-11-03
|
|
55
|
+
GKE Fair Chem System (FCS)
|
|
56
|
+
Managed Hosting
|
|
57
|
+
Skip for now
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The likely project is preselected. Press Enter to save it as a repo mapping; the draft is then redone with that repo's lines on the project. `Skip for now` asks again next time; `--no-prompt` never asks.
|
|
61
|
+
|
|
62
|
+
Other ways to map a repo, all without ids:
|
|
63
|
+
- Terminal UI: `/map --repo` (this folder) or `/map --repo ~/code/portal` opens the same picker; `/map --repo ~/code/portal Customer Portal` maps by name (a unique part of the name is enough).
|
|
64
|
+
- Assistant: `draft_from_commits` returns `repoSuggestions`, so the assistant asks "Is portal-web part of Customer Portal?" and calls `map_project` with `projectName` and `repos` after you say yes.
|
|
65
|
+
|
|
66
|
+
Mapped repos put their commits on that project. The hours come from what is still free on that project: booked minus logged. If the project is already full, its lines get 0h and the summary says so. Repos without a mapping fall back to ticket/keyword mappings and that day's bookings.
|
|
67
|
+
|
|
68
|
+
The assistant passes the draft's `projectOverrides` to `log_work` with the same text, so each line is logged to the project the draft chose.
|
|
69
|
+
|
|
70
|
+
## Handle A Possible Duplicate RO Entry
|
|
71
|
+
|
|
72
|
+
If a `log_work` preview shows `WARNING possible duplicate`, RO already has an entry on that date with the same worklog task, hours and description, or the batch repeats a line. This often happens after an agent re-ran or a batch failed partway.
|
|
73
|
+
|
|
74
|
+
Check `/query` (or `get_logwork`) first. If the work is already logged, drop the line and preview again. Only if it really is separate work, approve it explicitly: in the terminal UI answer yes to the duplicate question, or let the assistant confirm with `allowDuplicates: true`. Without that, apply writes nothing.
|
|
75
|
+
|
|
42
76
|
## Edit Existing Resource Optimiser Logwork
|
|
43
77
|
|
|
44
78
|
Find the RO logwork ID with `logwork query this-week`, `/query this-week`, or by asking the assistant to call `get_logwork`. Then use Terminal:
|
|
@@ -214,6 +248,12 @@ RO-only reminder at 18:00:
|
|
|
214
248
|
logwork reminder enable --time 18:00 --target ro
|
|
215
249
|
```
|
|
216
250
|
|
|
251
|
+
Add commit evidence from your repos (shown when RO hours are missing):
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
logwork reminder enable --repo ~/code/app --repo ~/code/api
|
|
255
|
+
```
|
|
256
|
+
|
|
217
257
|
Send a sample notification and inspect scheduler status:
|
|
218
258
|
|
|
219
259
|
```bash
|
package/docs/security.md
CHANGED
|
@@ -111,12 +111,32 @@ The runtime and local state live in `~/.logwork-cli` (`%USERPROFILE%\.logwork-cl
|
|
|
111
111
|
| `manual-drafts.json` | Terminal UI drafts. |
|
|
112
112
|
| `apply-ledger.json` | Sanitized apply history. |
|
|
113
113
|
| `update-state.json` | Update check cache: package name, latest SemVer, and check timestamp. Expires after 24 hours and contains no npm credentials. |
|
|
114
|
-
| `reminder.json`, `reminder-state.json` | Reminder config: enabled state, local time, target and
|
|
114
|
+
| `reminder.json`, `reminder-state.json` | Reminder config: enabled state, local time, target, weekdays and optional git repo paths for the commit summary. Last-run state: sanitized timestamps and status summaries. |
|
|
115
|
+
| `runtime.json` | The Node path and version `logwork setup` ran with, its install time and the package version. |
|
|
116
|
+
| `bin/logwork-launch` (macOS) | The launcher MCP configs and the reminder run. A `sh` script with the runtime path and the recorded Node path, nothing else. |
|
|
115
117
|
| `diagnostics/` | Sanitized diagnostics reports from `logwork doctor`. |
|
|
116
118
|
|
|
117
119
|
The apply ledger stores the target, flow target, batch ID, timestamp, workspace path, entry metadata, and submitted/failed/blocked status. It does not store credentials, cookies, or raw API responses, and token-like error text is redacted before writing.
|
|
118
120
|
|
|
119
|
-
The macOS launch agent and Windows scheduled task
|
|
121
|
+
The macOS launch agent runs `bin/logwork-launch reminder run`, and the Windows scheduled task runs a fixed `node.exe` with `bin/logwork.mjs reminder run`. They never contain RO tokens, Jira PATs, passwords, or API responses.
|
|
122
|
+
|
|
123
|
+
## MCP Client Configs
|
|
124
|
+
|
|
125
|
+
`logwork setup` and `logwork mcp install` edit the MCP config of the clients they find, after asking (or with `--yes`):
|
|
126
|
+
|
|
127
|
+
| Client | File or command |
|
|
128
|
+
| --- | --- |
|
|
129
|
+
| Claude Code | `claude mcp remove` / `claude mcp add --scope user` (or `~/.claude.json` without the CLI) |
|
|
130
|
+
| Cursor | `~/.cursor/mcp.json` |
|
|
131
|
+
| Codex | `~/.codex/config.toml` |
|
|
132
|
+
| VS Code | user `mcp.json` (`~/Library/Application Support/Code/User`, `%APPDATA%\Code\User`) |
|
|
133
|
+
| Google Antigravity | `~/.gemini/antigravity/mcp_config.json` |
|
|
134
|
+
|
|
135
|
+
- Only the `logwork` server entry is written, plus removal of an old `logwork-helper` entry (and, in Claude Code, a stale project-scope `logwork` entry). Other servers and settings are kept.
|
|
136
|
+
- The entry holds only `command` and `args` (the launcher or `node.exe`, the runtime path and `mcp`). No token, PAT, password, cookie or email is ever written to an MCP config.
|
|
137
|
+
- Before changing a file, it is copied to `<file>.logwork-backup-<YYYYMMDDHHmmss>` in the same folder, with the same permissions as the original. The new file is written atomically. Backups are never deleted automatically; remove them when you no longer need them. A backup can contain other servers' settings (for example API keys in their `env`), exactly as the original file does.
|
|
138
|
+
- A file that does not parse cleanly (comments, trailing commas, unusual TOML) is never written; the snippet is printed instead.
|
|
139
|
+
- `logwork mcp install --dry-run` and `logwork mcp status` only read.
|
|
120
140
|
|
|
121
141
|
## Safety Model
|
|
122
142
|
|
|
@@ -145,6 +165,7 @@ The macOS launch agent and Windows scheduled task contain only fixed Node and sc
|
|
|
145
165
|
- `reminder` with `action: "status"` is read-only.
|
|
146
166
|
- `enable`, `disable` and `test` require `confirm: true`. They never accept arbitrary scheduler commands, paths, JQL, or credentials.
|
|
147
167
|
- The background reminder reads RO and Jira sessions from the OS credential store only when it runs. Notification and state text are sanitized and never include raw API responses.
|
|
168
|
+
- With reminder repos, the background reminder runs read-only `git log` in those repos and shows only commit and repo counts. Commit subjects and paths are not put in the notification or the state file.
|
|
148
169
|
|
|
149
170
|
**Login and diagnostics**
|
|
150
171
|
- `login` never accepts credentials. It only opens or explains a terminal login.
|