@ghostpaw/questlog 0.9.1 → 0.10.1
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 +180 -18
- package/SKILL.md +161 -32
- package/dist/{chunk-3Y5F3SMB.js → chunk-55JAQORX.js} +245 -665
- package/dist/{questlog_skill_spec-LOQ2FNOF.js → chunk-D2W5MYNO.js} +9 -54
- package/dist/chunk-GVD6A3RR.js +108 -0
- package/dist/chunk-IL2QRKZL.js +14 -0
- package/dist/chunk-N7V7VUI5.js +982 -0
- package/dist/chunk-QYSIJ2YN.js +47 -0
- package/dist/{chunk-3B6FMHZU.js → chunk-ZHTX64KD.js} +24 -0
- package/dist/cli.js +1 -1
- package/dist/{cli_main-ELAKW6KW.js → cli_main-7AIEZV75.js} +136 -120
- package/dist/index.cjs +2046 -1393
- package/dist/index.d.cts +142 -11
- package/dist/index.d.ts +142 -11
- package/dist/index.js +2046 -1394
- package/dist/mcp-server.js +959 -386
- package/dist/mcp.cjs +810 -328
- package/dist/mcp.js +811 -329
- package/dist/open_questlog_db-LAEH7UDM.js +2 -0
- package/dist/questlog_skill_spec-HEW2B6EB.js +76 -0
- package/dist/run_hook_command-C42BQC36.js +95 -0
- package/dist/{serve_questlog_mcp-QSHMNNFT.js → serve_questlog_mcp-W3R63HW4.js} +14 -4
- package/dist/{skill_markdown-7HCMSJYR.js → skill_markdown-HXYQ3K6U.js} +34 -6
- package/package.json +6 -3
- package/skills/questlog/SKILL.md +161 -32
- package/skills/questlog/references/webhooks.md +91 -0
- package/dist/chunk-KRQDV4KF.js +0 -58
- package/dist/open_questlog_db-SH3DAU4C.js +0 -2
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
**Agent tasks as quests that finish only with a written outcome.**
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
|
|
10
|
+
curl -fsSL https://raw.githubusercontent.com/GhostPawJS/questlog/main/install.sh | sh
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
A unified task and calendar model for Node.js, built on SQLite.
|
|
@@ -16,14 +16,15 @@ Questlog treats tasks, events, deadlines, recurring commitments, and loose intak
|
|
|
16
16
|
|
|
17
17
|
## MCP server
|
|
18
18
|
|
|
19
|
-
Every client below starts the same stdio server: `
|
|
19
|
+
Every client below starts the same stdio server: `ghostpaw-questlog mcp`.
|
|
20
|
+
For npm-based environments, use `npx -y @ghostpaw/questlog mcp` (Node 24+).
|
|
20
21
|
Data lives in `~/.ghostpaw/questlog.db` unless the `GHOSTPAW_QUESTLOG_DB`
|
|
21
22
|
environment variable (absolute path) or `--db <path>` says otherwise.
|
|
22
23
|
|
|
23
24
|
**Claude Code**
|
|
24
25
|
|
|
25
26
|
```bash
|
|
26
|
-
claude mcp add ghostpaw-questlog --
|
|
27
|
+
claude mcp add ghostpaw-questlog -- ghostpaw-questlog mcp
|
|
27
28
|
```
|
|
28
29
|
|
|
29
30
|
or as a plugin, which also installs the skill:
|
|
@@ -37,8 +38,8 @@ or as a plugin, which also installs the skill:
|
|
|
37
38
|
|
|
38
39
|
```toml
|
|
39
40
|
[mcp_servers.ghostpaw-questlog]
|
|
40
|
-
command = "
|
|
41
|
-
args = ["
|
|
41
|
+
command = "ghostpaw-questlog"
|
|
42
|
+
args = ["mcp"]
|
|
42
43
|
```
|
|
43
44
|
|
|
44
45
|
**Cursor** (`.cursor/mcp.json`), **Claude Desktop** (`claude_desktop_config.json`)
|
|
@@ -48,8 +49,8 @@ or a project `.mcp.json`:
|
|
|
48
49
|
{
|
|
49
50
|
"mcpServers": {
|
|
50
51
|
"ghostpaw-questlog": {
|
|
51
|
-
"command": "
|
|
52
|
-
"args": ["
|
|
52
|
+
"command": "ghostpaw-questlog",
|
|
53
|
+
"args": ["mcp"]
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
56
|
}
|
|
@@ -65,10 +66,10 @@ initialize-based revisions 2025-11-25, 2025-06-18, 2025-03-26 and 2024-11-05.
|
|
|
65
66
|
|
|
66
67
|
## CLI
|
|
67
68
|
|
|
68
|
-
Install
|
|
69
|
+
Install the [release binary](#install) for `ghostpaw-questlog` (`questlog` is an alias).
|
|
69
70
|
|
|
70
71
|
```bash
|
|
71
|
-
questlog add
|
|
72
|
+
questlog add "Review release notes" --tag release --due 2030-01-02
|
|
72
73
|
questlog list --limit 10
|
|
73
74
|
questlog search release notes --limit 5
|
|
74
75
|
questlog show 1
|
|
@@ -114,32 +115,74 @@ an installation hint on older Node versions, including for help and version.
|
|
|
114
115
|
Copy `skills/questlog/` into your agent's skills folder, or print it:
|
|
115
116
|
|
|
116
117
|
```bash
|
|
117
|
-
|
|
118
|
+
ghostpaw-questlog skill > SKILL.md
|
|
118
119
|
```
|
|
119
120
|
|
|
120
121
|
## Install
|
|
121
122
|
|
|
122
|
-
|
|
123
|
+
### Release binary (default)
|
|
124
|
+
|
|
125
|
+
Each line downloads the latest release asset, checks it against the release’s SHA256SUMS and installs it on the PATH (~/.local/bin on Linux/macOS; the Windows script adds its folder to the user PATH).
|
|
126
|
+
|
|
127
|
+
These lines never edit ~/.profile or other shell startup files: `export PATH` applies to the current shell only. To keep it, add `export PATH="$HOME/.local/bin:$PATH"` to your shell profile yourself.
|
|
128
|
+
|
|
129
|
+
linux-x64:
|
|
123
130
|
|
|
124
131
|
```sh
|
|
125
|
-
|
|
126
|
-
|
|
132
|
+
curl -fsSL https://raw.githubusercontent.com/GhostPawJS/questlog/main/install.sh | sh -s -- --target linux-x64 && export PATH="$HOME/.local/bin:$PATH"
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
linux-arm64:
|
|
136
|
+
|
|
137
|
+
```sh
|
|
138
|
+
curl -fsSL https://raw.githubusercontent.com/GhostPawJS/questlog/main/install.sh | sh -s -- --target linux-arm64 && export PATH="$HOME/.local/bin:$PATH"
|
|
127
139
|
```
|
|
128
140
|
|
|
129
|
-
|
|
130
|
-
`node:sqlite` module, so there are no runtime dependencies.
|
|
141
|
+
darwin-arm64:
|
|
131
142
|
|
|
132
|
-
|
|
133
|
-
|
|
143
|
+
```sh
|
|
144
|
+
curl -fsSL https://raw.githubusercontent.com/GhostPawJS/questlog/main/install.sh | sh -s -- --target darwin-arm64 && export PATH="$HOME/.local/bin:$PATH"
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
darwin-x64:
|
|
134
148
|
|
|
135
149
|
```sh
|
|
136
|
-
curl -fsSL https://raw.githubusercontent.com/GhostPawJS/questlog/main/install.sh | sh
|
|
150
|
+
curl -fsSL https://raw.githubusercontent.com/GhostPawJS/questlog/main/install.sh | sh -s -- --target darwin-x64 && export PATH="$HOME/.local/bin:$PATH"
|
|
137
151
|
```
|
|
138
152
|
|
|
153
|
+
windows-x64 (PowerShell; persistently adds its folder to the user PATH):
|
|
154
|
+
|
|
139
155
|
```powershell
|
|
140
156
|
irm https://raw.githubusercontent.com/GhostPawJS/questlog/main/install.ps1 | iex
|
|
141
157
|
```
|
|
142
158
|
|
|
159
|
+
Pinned to a release:
|
|
160
|
+
|
|
161
|
+
```sh
|
|
162
|
+
curl -fsSL https://raw.githubusercontent.com/GhostPawJS/questlog/main/install.sh | sh -s -- --target linux-x64 --version 0.10.1 && export PATH="$HOME/.local/bin:$PATH"
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
To skip the persistent Windows user PATH edit (the installer still installs and prints the folder to add):
|
|
166
|
+
|
|
167
|
+
```powershell
|
|
168
|
+
$env:GHOSTPAW_NO_MODIFY_PATH=1; irm https://raw.githubusercontent.com/GhostPawJS/questlog/main/install.ps1 | iex
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
```text
|
|
172
|
+
$ ghostpaw-questlog --version
|
|
173
|
+
questlog 0.10.1 (binary, linux-x64)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Scripts that compare versions should use `--version --short` or `--version --json`.
|
|
177
|
+
|
|
178
|
+
Standalone binaries are available from [GitHub Releases](https://github.com/GhostPawJS/questlog/releases).
|
|
179
|
+
|
|
180
|
+
A session with the 0.9.1 linux-x64 binary against a fresh database:
|
|
181
|
+
|
|
182
|
+

|
|
183
|
+
|
|
184
|
+
The same session as an [animated GIF](https://raw.githubusercontent.com/GhostPawJS/questlog/main/docs/assets/cli.gif).
|
|
185
|
+
|
|
143
186
|
Other release installers:
|
|
144
187
|
|
|
145
188
|
```sh
|
|
@@ -193,6 +236,27 @@ download on macOS, remove quarantine with
|
|
|
193
236
|
Linux binaries require glibc 2.28+; use npx on Alpine.
|
|
194
237
|
See the [binary build workflow](.github/workflows/release-binaries.yml).
|
|
195
238
|
|
|
239
|
+
### npx / npm (for npm-based environments)
|
|
240
|
+
|
|
241
|
+
The [npm package](https://www.npmjs.com/package/@ghostpaw/questlog) requires Node 24+:
|
|
242
|
+
|
|
243
|
+
```sh
|
|
244
|
+
npx -y @ghostpaw/questlog --help
|
|
245
|
+
npm install -g @ghostpaw/questlog
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Library (for harnesses embedding it in code)
|
|
249
|
+
|
|
250
|
+
```sh
|
|
251
|
+
npm install @ghostpaw/questlog
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
```ts
|
|
255
|
+
import { initQuestlogTables, read, write } from '@ghostpaw/questlog';
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
See [library usage](#quick-start). The library uses built-in `node:sqlite` with zero runtime dependencies.
|
|
259
|
+
|
|
196
260
|
## Quick Start
|
|
197
261
|
|
|
198
262
|
```ts
|
|
@@ -450,3 +514,101 @@ If this package helps your project, consider sponsoring its maintenance:
|
|
|
450
514
|
---
|
|
451
515
|
|
|
452
516
|
**[Anonyfox](https://anonyfox.com) • [MIT License](LICENSE)**
|
|
517
|
+
|
|
518
|
+
## Webhooks
|
|
519
|
+
|
|
520
|
+
Configure opt-in outbound wakes with the release binary. No server or scheduler is started.
|
|
521
|
+
With no targets, tick makes no network calls. Targets and retry state live in the database.
|
|
522
|
+
|
|
523
|
+
```sh
|
|
524
|
+
questlog hook add https://example.org/wake --min-gap 60
|
|
525
|
+
questlog hook add https://example.org/team --tag work --events quest.due,quest.overdue --secret-stdin
|
|
526
|
+
questlog hook label work
|
|
527
|
+
questlog hook list
|
|
528
|
+
questlog tick --dry-run
|
|
529
|
+
questlog tick
|
|
530
|
+
questlog watch --interval 60
|
|
531
|
+
questlog hook test 1
|
|
532
|
+
questlog review deliveries
|
|
533
|
+
questlog show 12
|
|
534
|
+
questlog hook remove 1
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
Save the signing secret printed once by `hook add` (including its `--json` result).
|
|
538
|
+
`--secret-stdin` reads a supplied secret from standard input; there is no secret flag.
|
|
539
|
+
List output redacts URL userinfo and query strings. Removal deletes the target and its deliveries.
|
|
540
|
+
A target covers the database unless `--tag` restricts it to quests with that tag;
|
|
541
|
+
rumors have no tags and reach database targets only. `--events` defaults to all five events.
|
|
542
|
+
The label defaults to the database filename without directory or extension (`questlog` for memory).
|
|
543
|
+
Only use labels suitable for disclosure to the receiver.
|
|
544
|
+
|
|
545
|
+
For cron:
|
|
546
|
+
|
|
547
|
+
```cron
|
|
548
|
+
* * * * * questlog tick
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
Cron's PATH may need `$HOME/.local/bin/questlog tick --db /path/to/quests.db`.
|
|
552
|
+
`watch` repeats tick (default 60 seconds, minimum 5), finishing its current tick on SIGINT/SIGTERM.
|
|
553
|
+
Tick exits 0 after running even when deliveries need retrying. Dry runs roll back all changes,
|
|
554
|
+
including repeatable materialization, and make no network calls.
|
|
555
|
+
|
|
556
|
+
Events are detected from the model at tick time:
|
|
557
|
+
|
|
558
|
+
- `quest.due`: an unresolved, undeleted quest reaches its effective due time (own `due_at`, otherwise its undeleted questline's due time).
|
|
559
|
+
- `quest.overdue`: that effective deadline is strictly earlier than now and the quest remains unresolved.
|
|
560
|
+
- `quest.unblocked`: an unresolved quest is available, all active prerequisites have succeeded or been deleted, and at least one prerequisite succeeded after its unlock was installed. Occurrence time is the latest active prerequisite success or not-before time, whichever is later.
|
|
561
|
+
- `repeatable.spawned`: a concrete repeatable instance was created; occurrence time is its creation time. Tick first materializes due anchors through the existing spawn operation.
|
|
562
|
+
- `rumor.captured`: an undeleted rumor was created; occurrence time is its creation time, even if subsequently settled or dismissed.
|
|
563
|
+
|
|
564
|
+
Each type, entity and occurrence timestamp has a persistent unique event key. Repeated ticks
|
|
565
|
+
and restarts do not create another occurrence. Changes removed before any tick cannot be
|
|
566
|
+
reconstructed. Occurrences earlier than target creation are excluded, preventing backlog floods.
|
|
567
|
+
Tags are evaluated when assigning an event. Already assigned events retain their batch membership.
|
|
568
|
+
|
|
569
|
+
One POST batch per target per tick contains only identifiers, types, timestamps, and the DB label:
|
|
570
|
+
|
|
571
|
+
```json
|
|
572
|
+
{"type":"questlog.events","db":"work","deliveryId":"d_…","sentAt":"2026-10-28T10:00:00.000Z","events":[{"id":"e_…","type":"quest.due","questId":12,"occurredAt":"2026-10-28T09:59:00.000Z"}]}
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
Headers are `content-type: application/json`, `user-agent: questlog/<version>`,
|
|
576
|
+
`x-questlog-delivery: <deliveryId>`, `x-questlog-timestamp: <unix seconds>`, and
|
|
577
|
+
`x-questlog-signature: sha256=<hex HMAC-SHA256(secret, timestamp + "." + rawBody)>`.
|
|
578
|
+
No titles, objectives, details, or tag text are sent. `hook test` sends a logged `hook.test`
|
|
579
|
+
event immediately, ignoring the min gap. Add and test are CLI-only in the tool facade;
|
|
580
|
+
`manage_hooks` supports list, remove, tick (with `dry_run`), and deliveries.
|
|
581
|
+
|
|
582
|
+
2xx delivers the batch. Requests time out after 5 seconds. Other responses, timeouts, and
|
|
583
|
+
network errors retry after 30 seconds, 1 minute, 2 minutes, 4 minutes, and so on, capped
|
|
584
|
+
at 1 hour, plus less than 1 second jitter. The target's min gap also applies to retries.
|
|
585
|
+
Eight unsuccessful attempts mark a delivery failed. Retries retain the delivery id and events.
|
|
586
|
+
Pending batches wait behind retries. Only the last 500 delivered entries per target are kept;
|
|
587
|
+
pending and failed entries are retained. Transactions and two-minute leases prevent overlapping
|
|
588
|
+
ticks from claiming the same delivery. A crash after receipt but before recording success can
|
|
589
|
+
cause another request: receivers must dedupe by delivery id.
|
|
590
|
+
|
|
591
|
+
### Verifying a delivery
|
|
592
|
+
|
|
593
|
+
Compute HMAC-SHA256 over `timestamp + "." + rawBody` with the secret and compare in constant
|
|
594
|
+
time. Reject timestamps older than 5 minutes (and timestamps too far in the future), then
|
|
595
|
+
dedupe on `x-questlog-delivery`. Use durable deduplication storage in a production receiver.
|
|
596
|
+
This 15-line Node example uses an in-memory set:
|
|
597
|
+
|
|
598
|
+
```js
|
|
599
|
+
import { createHmac, timingSafeEqual } from 'node:crypto';
|
|
600
|
+
import { createServer } from 'node:http';
|
|
601
|
+
const secret = process.env.WEBHOOK_SECRET, seen = new Set();
|
|
602
|
+
createServer(async (req, res) => {
|
|
603
|
+
const chunks = []; for await (const chunk of req) chunks.push(chunk);
|
|
604
|
+
const rawBody = Buffer.concat(chunks), h = req.headers;
|
|
605
|
+
const timestamp = h['x-questlog-timestamp'], id = h['x-questlog-delivery'];
|
|
606
|
+
const age = Date.now() / 1000 - Number(timestamp);
|
|
607
|
+
const expected = createHmac('sha256', secret).update(timestamp + '.').update(rawBody).digest();
|
|
608
|
+
const signature = String(h['x-questlog-signature'] || '');
|
|
609
|
+
const actual = Buffer.from(signature.slice(7), 'hex');
|
|
610
|
+
if (!id || !/^\d+$/.test(timestamp) || age > 300 || age < -300 || !/^sha256=[a-f0-9]{64}$/.test(signature) || actual.length !== expected.length || !timingSafeEqual(actual, expected)) { res.writeHead(401).end(); return; }
|
|
611
|
+
if (!seen.has(id)) { seen.add(id); console.log(JSON.parse(rawBody)); }
|
|
612
|
+
res.writeHead(204).end();
|
|
613
|
+
}).listen(8080, '127.0.0.1');
|
|
614
|
+
```
|