worklog
by luanAfons0
README.md
# Worklog
A FirstMate Plugin that keeps what you work on from one Meeting to the next,
and the free Notes that belong to no Meeting.
Read [`CONTEXT.md`](CONTEXT.md) for the words this project uses — Entry, Note,
Status, Meeting, Cycle — and [`docs/adr/`](docs/adr) for why a Cycle starts
when Scheduler says so and why the data is in SQLite.
## Install it
One command, from its git URL. The files land in FirstMate's Shelf, the Plugin
is registered in the same step, and nothing it ships is run:
```sh
firstmate install https://github.com/luanAfons0/worklog.git worklog
systemctl --user restart firstmate
```
Then open the Index Page, find `worklog`, and open its Plugin Page.
To let Scheduler start a Cycle at every Meeting, record a Grant from Scheduler
to Worklog and restart again. A Grant is one way and covers one pair:
```sh
firstmate grant scheduler worklog
systemctl --user restart firstmate
```
Developing it instead? Register the directory where it already lives:
```sh
node src/cli.ts add worklog /absolute/path/to/worklog # in FirstMate
```
See [`CONTRIBUTING.md`](CONTRIBUTING.md) for the rest.
The Plugin Page has three tabs: **Cycle**, **Earlier Cycles** and **Notes**.
The keys 1, 2 and 3 choose one, and N starts a new Entry.
Drag an Entry to another column to give it that Status, or up and down to set
its place in the column; the Meeting lists each section in that order. In a Note, Shift+Enter
saves it.
Edit an Entry or a Note and its text stays formatted, as in Notion. Click a
block to type in it: that block alone shows its Markdown, and it is formatted
again the moment you leave it. Enter in a list starts the next item; Enter on
an empty item or an empty line starts a new block. Tab and Shift+Tab indent a
list item. Up and Down at the edge of a block go to the next one. Click a
checkbox to tick it. Ctrl+click opens a link. The first Esc leaves the block,
and the second closes the dialog.
It needs Node 24 or newer, for TypeScript with no build step and for
`node:sqlite`. The Host starts `mcp.ts` with its own Node, on Windows and on
Linux alike, so the Plugin needs no Node of its own there. If that Node is
older than 24, the Plugin says so in one sentence and is Stopped. `mcp` is the `sh`
wrapper for a `wsl` Place, where the Host starts `./mcp`. The Host's service
`PATH` often has only an older Node, so `mcp` looks for one in this order:
`WORKLOG_NODE`, `node` on `PATH`, then every Node under nvm. With none, it says
so in one sentence and the Plugin is Stopped.
## What it keeps
- An **Entry** is one thing you work on: a title, an optional Markdown body,
a Status — `Todo`, `In Progress`, `In Review` or `Done` — and an optional
**Link**: the http or https address of the issue or pull request it is
about, in Linear, GitHub or elsewhere. The Entry card shows it as a small
mark in its top-right corner (Linear's, GitHub's, or a plain link) that
opens it in a new tab.
- A **Cycle** is the time from one Meeting to the next, named by the moment it
started. A new Entry goes into the current Cycle. The first Cycle starts by
itself the first time Worklog needs one.
- When a Cycle starts, every Entry that is not `Done` moves into it with its
Status unchanged. It is the same Entry, not a copy. `Done`
Entries stay in the Cycle they were done in.
- An Entry that is not `Done` is always in the current Cycle. Set a `Done`
Entry in an earlier Cycle back to any other Status, and it moves into the
current Cycle in the same write.
- Every Cycle is kept. The Page lists the earlier ones, newest first, each
named by the moment it started; open one to see what was Done in it.
- A **Note** is free Markdown text. It has no Status and belongs to no Cycle,
so it never moves. Notes are listed newest first.
Everything lives in one file, `worklog.db`, in the Plugin directory. Git ignores
it. Worklog starts empty. A Plugin directory from before the rename to Worklog
holds `daily.db` instead; the first start renames it to `worklog.db`, with every
Cycle, Entry and Note in it.
## The Popup form
`web/new.html` is a small second page: choose Entry or Note, type, press
Enter. An Entry has a title, a body, an optional Link and a Status that starts
at `Todo`; a Note has only a body. Shift+Enter is a new line in the body. After a save the page
goes to the main Plugin Page, `./`.
It is the page a FirstMate Shortcut opens in a Popup. Going to `./` leaves
the Popup's address, so the Popup hides by itself. In a normal browser, at
`/p/worklog/new.html`, it lands on the main page instead. Once the Shortcut work
lands in FirstMate, bind it with:
```sh
node src/cli.ts bind <keys> worklog new.html # in FirstMate
```
## Tools
Every tool answers its data twice: as JSON text, and as `structuredContent`.
A tool given bad input answers a JSON-RPC error with one sentence.
| Tool | Arguments | Answers |
| -------------- | ------------------------------------------- | -------------------------------- |
| `start_cycle` | none | one sentence, and `{ cycle, moved, said }` |
| `get_cycle` | optional `id` | that Cycle, or the current one, and its Entries |
| `list_cycles` | none | `{ cycles }`, newest first, each with counts by Status |
| `create_entry` | `title`, `status`, optional `body`, `link` | the new Entry |
| `update_entry` | `id`, and any of `title`, `body`, `status`, `link` | the Entry as it now is |
| `move_entry` | `id`, and `status`, `before` (optional) | the Entry in its new place |
| `delete_entry` | `id` | the Entry that is gone |
| `meeting_markdown` | none | the Markdown, and `{ markdown, done, inReview, workingOn }` |
| `list_notes` | none | `{ notes }`, newest first |
| `create_note` | `body`, `title` (optional) | the new Note |
| `update_note` | `id`, `body`, `title` (optional) | the Note as it now is |
| `delete_note` | `id` | the Note that is gone |
`start_cycle` is the tool a Scheduler Job calls at every Meeting, under a
Grant from Scheduler to Worklog. Every call starts exactly one Cycle
(ADR-0001), and its text is one sentence, because a Scheduler Run keeps one:
`Started the Cycle of Tue 23 Sep 10:00 and moved 4 Entries into it.` The
moment is on the clock of the machine Worklog runs on. The Page's **Start a new
Cycle** button calls the same tool, after one question, for the day Scheduler
did not.
`meeting_markdown` decides what the Page's **Start presentation** shows: one
Entry at a time, full window, for the Statuses chosen at the top. It has a
"Done" section — the Entries Done in the Cycle before the current one, then
those already Done in the current one — an "In review" section, when
anything is `In Review` — and a "Working on" section — the current Cycle's
`In Progress` Entries, then its `Todo` ones, each in the order of its column. It lists titles only;
the title of an Entry with a Link is a Markdown link to it, `[title](link)`. Present after the Meeting's `start_cycle`
has run; before, "Done" also holds what was reported last time.
Every Entry a tool answers carries `link`: its address, or `null` when it has
none. A `link` is an absolute `http:` or `https:` address of at most 2048
characters, kept trimmed; any other is refused. On `update_entry`, a `link` of
`null` or `""` takes the Link away.
Any Status may go to any other. A `body` of `null` or `""` takes the body
away. Bodies are Markdown; the Page shows them formatted with `web/markdown.js`,
a small renderer written for this Plugin, so the Page loads nothing from a CDN.
## Running it
`mcp.ts` is the Plugin Server, as the Host runs it with its own Node: MCP over
stdio. `./mcp` is the same, for a `wsl` Place. `npm test`
runs every test; `npm run typecheck` checks the types.
## Licence
MIT. See [`LICENSE.md`](LICENSE.md).
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessOutdated data