@hanna84/mcp-writing 1.3.8 → 1.4.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.
Files changed (4) hide show
  1. package/CHANGELOG.md +84 -55
  2. package/README.md +194 -26
  3. package/index.js +40 -0
  4. package/package.json +5 -2
package/CHANGELOG.md CHANGED
@@ -1,101 +1,130 @@
1
- # Changelog
1
+ ### Changelog
2
2
 
3
- ## [1.3.8](https://github.com/hannasdev/mcp-writing/compare/v1.3.7...v1.3.8) (2026-04-18)
3
+ All notable changes to this project will be documented in this file. Dates are displayed in UTC.
4
4
 
5
+ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
5
6
 
6
- ### Miscellaneous Chores
7
+ #### [v1.4.1](https://github.com/hannasdev/mcp-writing/compare/v1.4.0...v1.4.1)
7
8
 
8
- * enable auto-merge for Release Please version PRs ([#24](https://github.com/hannasdev/mcp-writing/issues/24)) ([07981af](https://github.com/hannasdev/mcp-writing/commit/07981af84c4029cb25aef1947f301eb172df3d3a))
9
+ - fix: correct release increment regex quoting on main [`#32`](https://github.com/hannasdev/mcp-writing/pull/32)
10
+ - fix: support legacy release token secret name [`#31`](https://github.com/hannasdev/mcp-writing/pull/31)
11
+ - chore: migrate release automation from Release Please to release-it [`#30`](https://github.com/hannasdev/mcp-writing/pull/30)
9
12
 
10
- ## [1.3.7](https://github.com/hannasdev/mcp-writing/compare/v1.3.6...v1.3.7) (2026-04-18)
13
+ #### [v1.4.0](https://github.com/hannasdev/mcp-writing/compare/v1.3.8...v1.4.0)
11
14
 
15
+ > 18 April 2026
12
16
 
13
- ### Miscellaneous Chores
17
+ - chore(main): release 1.4.0 [`#29`](https://github.com/hannasdev/mcp-writing/pull/29)
18
+ - docs: streamline README for first-time onboarding [`#28`](https://github.com/hannasdev/mcp-writing/pull/28)
19
+ - docs: streamline README for first-time onboarding [`#27`](https://github.com/hannasdev/mcp-writing/pull/27)
20
+ - docs: streamline README for first-time onboarding [`#26`](https://github.com/hannasdev/mcp-writing/pull/26)
21
+ - feat: add runtime write-access diagnostics for onboarding [`434c453`](https://github.com/hannasdev/mcp-writing/commit/434c45323b7662312cff8cc24e2c8ee2c0fd8745)
14
22
 
15
- * **ci:** remove npm whoami diagnostic step ([65435e9](https://github.com/hannasdev/mcp-writing/commit/65435e9c8cfa829ceb6937904250c46afc45b54c))
23
+ #### [v1.3.8](https://github.com/hannasdev/mcp-writing/compare/v1.3.7...v1.3.8)
16
24
 
17
- ## [1.3.6](https://github.com/hannasdev/mcp-writing/compare/v1.3.5...v1.3.6) (2026-04-18)
25
+ > 18 April 2026
18
26
 
27
+ - chore(main): release 1.3.8 [`#25`](https://github.com/hannasdev/mcp-writing/pull/25)
28
+ - chore: enable auto-merge for Release Please version PRs [`#24`](https://github.com/hannasdev/mcp-writing/pull/24)
19
29
 
20
- ### Bug Fixes
30
+ #### [v1.3.7](https://github.com/hannasdev/mcp-writing/compare/v1.3.6...v1.3.7)
21
31
 
22
- * **ci:** restore npm trusted publishing auth config ([f043368](https://github.com/hannasdev/mcp-writing/commit/f0433681e984e34d1c38725f2d85dc3d14031626))
32
+ > 18 April 2026
23
33
 
24
- ## [1.3.5](https://github.com/hannasdev/mcp-writing/compare/v1.3.4...v1.3.5) (2026-04-18)
34
+ - chore(main): release 1.3.7 [`#22`](https://github.com/hannasdev/mcp-writing/pull/22)
35
+ - docs: add prerequisites, setup verification, and troubleshooting guide [`#23`](https://github.com/hannasdev/mcp-writing/pull/23)
36
+ - chore(ci): remove npm whoami diagnostic step [`65435e9`](https://github.com/hannasdev/mcp-writing/commit/65435e9c8cfa829ceb6937904250c46afc45b54c)
25
37
 
38
+ #### [v1.3.6](https://github.com/hannasdev/mcp-writing/compare/v1.3.5...v1.3.6)
26
39
 
27
- ### Bug Fixes
40
+ > 18 April 2026
28
41
 
29
- * **ci:** force OIDC-only npm publish auth ([c9f1216](https://github.com/hannasdev/mcp-writing/commit/c9f1216f2d3aa49fcc2aad5e6c4032962ad843d1))
42
+ - chore(main): release 1.3.6 [`#21`](https://github.com/hannasdev/mcp-writing/pull/21)
43
+ - fix(ci): add npm whoami diagnostic step [`9d6b13e`](https://github.com/hannasdev/mcp-writing/commit/9d6b13e924e802df25099b42a178a772153e66c3)
44
+ - fix: add repository url for npm provenance [`50c2d21`](https://github.com/hannasdev/mcp-writing/commit/50c2d216776cb3117e67b3ff1cc65f1192fb0955)
45
+ - fix(ci): restore npm trusted publishing auth config [`f043368`](https://github.com/hannasdev/mcp-writing/commit/f0433681e984e34d1c38725f2d85dc3d14031626)
30
46
 
31
- ## [1.3.4](https://github.com/hannasdev/mcp-writing/compare/v1.3.3...v1.3.4) (2026-04-18)
47
+ #### [v1.3.5](https://github.com/hannasdev/mcp-writing/compare/v1.3.4...v1.3.5)
32
48
 
49
+ > 18 April 2026
33
50
 
34
- ### Bug Fixes
51
+ - chore(main): release 1.3.5 [`#20`](https://github.com/hannasdev/mcp-writing/pull/20)
52
+ - fix(ci): force OIDC-only npm publish auth [`c9f1216`](https://github.com/hannasdev/mcp-writing/commit/c9f1216f2d3aa49fcc2aad5e6c4032962ad843d1)
35
53
 
36
- * **ci:** use tag trigger for npm publish (matches n8n pattern) ([#18](https://github.com/hannasdev/mcp-writing/issues/18)) ([a3c5992](https://github.com/hannasdev/mcp-writing/commit/a3c5992e8cb560aa79b554389d41457fcf3c0cfd))
54
+ #### [v1.3.4](https://github.com/hannasdev/mcp-writing/compare/v1.3.3...v1.3.4)
37
55
 
38
- ## [1.3.3](https://github.com/hannasdev/mcp-writing/compare/v1.3.2...v1.3.3) (2026-04-18)
56
+ > 18 April 2026
39
57
 
58
+ - chore(main): release 1.3.4 [`#19`](https://github.com/hannasdev/mcp-writing/pull/19)
59
+ - fix(ci): use tag trigger for npm publish (matches n8n pattern) [`#18`](https://github.com/hannasdev/mcp-writing/pull/18)
40
60
 
41
- ### Bug Fixes
61
+ #### [v1.3.3](https://github.com/hannasdev/mcp-writing/compare/v1.3.2...v1.3.3)
42
62
 
43
- * **ci:** use tag trigger for npm publish (matches n8n pattern) ([6841de7](https://github.com/hannasdev/mcp-writing/commit/6841de78a90c3b4c121761d28a09b02f9d360a96))
63
+ > 18 April 2026
44
64
 
45
- ## [1.3.2](https://github.com/hannasdev/mcp-writing/compare/v1.3.1...v1.3.2) (2026-04-18)
65
+ - chore(main): release 1.3.3 [`#17`](https://github.com/hannasdev/mcp-writing/pull/17)
66
+ - fix(ci): use tag trigger for npm publish (matches n8n pattern) [`6841de7`](https://github.com/hannasdev/mcp-writing/commit/6841de78a90c3b4c121761d28a09b02f9d360a96)
46
67
 
68
+ #### [v1.3.2](https://github.com/hannasdev/mcp-writing/compare/v1.3.1...v1.3.2)
47
69
 
48
- ### Bug Fixes
70
+ > 18 April 2026
49
71
 
50
- * **ci:** publish from main release commits for npm trusted publishing ([135ab25](https://github.com/hannasdev/mcp-writing/commit/135ab254fb91ee6427a79cdecdc5b9bf55cfb4d1))
72
+ - chore(main): release 1.3.2 [`#16`](https://github.com/hannasdev/mcp-writing/pull/16)
73
+ - docs(readme): add real-world scenarios; fix publish workflow yaml [`3566905`](https://github.com/hannasdev/mcp-writing/commit/3566905d6f060eed5c35be29f73560bc4d74af27)
74
+ - fix(ci): publish from main release commits for npm trusted publishing [`135ab25`](https://github.com/hannasdev/mcp-writing/commit/135ab254fb91ee6427a79cdecdc5b9bf55cfb4d1)
51
75
 
52
- ## [1.3.1](https://github.com/hannasdev/mcp-writing/compare/v1.3.0...v1.3.1) (2026-04-18)
76
+ #### [v1.3.1](https://github.com/hannasdev/mcp-writing/compare/v1.3.0...v1.3.1)
53
77
 
78
+ > 18 April 2026
54
79
 
55
- ### Bug Fixes
80
+ - chore(main): release 1.3.1 [`#15`](https://github.com/hannasdev/mcp-writing/pull/15)
81
+ - chore: generate integration fixtures at runtime and remove test-sync [`#14`](https://github.com/hannasdev/mcp-writing/pull/14)
82
+ - fix(ci): set npm environment for trusted publishing [`b75fb08`](https://github.com/hannasdev/mcp-writing/commit/b75fb0897dbbbd9df2d136cbb78a06218f0c0b50)
56
83
 
57
- * **ci:** set npm environment for trusted publishing ([b75fb08](https://github.com/hannasdev/mcp-writing/commit/b75fb0897dbbbd9df2d136cbb78a06218f0c0b50))
84
+ #### [v1.3.0](https://github.com/hannasdev/mcp-writing/compare/v1.2.0...v1.3.0)
58
85
 
86
+ > 18 April 2026
59
87
 
60
- ### Miscellaneous Chores
88
+ - chore(main): release 1.3.0 [`#13`](https://github.com/hannasdev/mcp-writing/pull/13)
89
+ - feat: formalize non-draft content and stable Scrivener imports [`#12`](https://github.com/hannasdev/mcp-writing/pull/12)
61
90
 
62
- * generate integration fixtures at runtime and remove test-sync ([#14](https://github.com/hannasdev/mcp-writing/issues/14)) ([0ff5024](https://github.com/hannasdev/mcp-writing/commit/0ff5024f0c3724b099035a6f76fbe4c517870652))
91
+ #### [v1.2.0](https://github.com/hannasdev/mcp-writing/compare/v1.1.1...v1.2.0)
63
92
 
64
- ## [1.3.0](https://github.com/hannasdev/mcp-writing/compare/v1.2.0...v1.3.0) (2026-04-17)
93
+ > 17 April 2026
65
94
 
95
+ - chore(main): release 1.2.0 [`#11`](https://github.com/hannasdev/mcp-writing/pull/11)
96
+ - feat: Phase 3 git-backed prose editing, runtime config tool, startup path logging [`f30a7c8`](https://github.com/hannasdev/mcp-writing/commit/f30a7c8b5e5aaf070b0b6cfaec38479141c5f60b)
66
97
 
67
- ### Features
98
+ #### [v1.1.1](https://github.com/hannasdev/mcp-writing/compare/v1.1.0...v1.1.1)
68
99
 
69
- * formalize non-draft content and stable Scrivener imports ([#12](https://github.com/hannasdev/mcp-writing/issues/12)) ([70b4beb](https://github.com/hannasdev/mcp-writing/commit/70b4bebd0d3cd823ffe3a9251f59f9a0c0e5f12f))
100
+ > 16 April 2026
70
101
 
71
- ## [1.2.0](https://github.com/hannasdev/mcp-writing/compare/v1.1.1...v1.2.0) (2026-04-17)
102
+ - chore(main): release 1.1.1 [`#9`](https://github.com/hannasdev/mcp-writing/pull/9)
103
+ - fix: use dedicated token for release-please workflow [`#10`](https://github.com/hannasdev/mcp-writing/pull/10)
104
+ - chore: include chore commits in release automation [`#8`](https://github.com/hannasdev/mcp-writing/pull/8)
105
+ - chore: keep reusable MCP validation scripts [`#7`](https://github.com/hannasdev/mcp-writing/pull/7)
106
+ - chore: trigger CI for release-please branches [`#6`](https://github.com/hannasdev/mcp-writing/pull/6)
107
+ - chore: include chore commits in release-please [`c437850`](https://github.com/hannasdev/mcp-writing/commit/c4378501ee7dc29d582ce78bc1d227927e719810)
108
+ - chore: fix lint in MCP validation scripts [`2b2385e`](https://github.com/hannasdev/mcp-writing/commit/2b2385e3eddd8fd30716d0f72dfa6346ec2d6e5f)
109
+ - chore: run CI on release-please branch pushes [`856063c`](https://github.com/hannasdev/mcp-writing/commit/856063c85047c164f857f598520f57dffe215d4a)
72
110
 
111
+ #### [v1.1.0](https://github.com/hannasdev/mcp-writing/compare/v1.0.0...v1.1.0)
73
112
 
74
- ### Features
113
+ > 16 April 2026
75
114
 
76
- * Phase 3 git-backed prose editing, runtime config tool, startup path logging ([f30a7c8](https://github.com/hannasdev/mcp-writing/commit/f30a7c8b5e5aaf070b0b6cfaec38479141c5f60b))
115
+ - chore(main): release 1.1.0 [`#5`](https://github.com/hannasdev/mcp-writing/pull/5)
116
+ - feat: stable Scrivener identity and reorder reconciliation [`#4`](https://github.com/hannasdev/mcp-writing/pull/4)
117
+ - chore: add ESLint, release-please, and automated npm publish [`#3`](https://github.com/hannasdev/mcp-writing/pull/3)
118
+ - Publish to npm as @hanna84/mcp-writing [`#2`](https://github.com/hannasdev/mcp-writing/pull/2)
119
+ - Mark package as private [`#1`](https://github.com/hannasdev/mcp-writing/pull/1)
120
+ - chore: trigger CI checks for release PR [`5191fcc`](https://github.com/hannasdev/mcp-writing/commit/5191fccc7c9643a7d7ac32da3a407a0e512fa287)
121
+ - Track package-lock.json; remove from gitignore [`090b0af`](https://github.com/hannasdev/mcp-writing/commit/090b0af5b8e532dc88013ae46d5cd6237221cb26)
122
+ - chore: add ESLint, release-please, and automated npm publish workflow [`9e8f8d7`](https://github.com/hannasdev/mcp-writing/commit/9e8f8d7d4832cb1f1f0710351f9c53cf008850bb)
77
123
 
78
- ## [1.1.1](https://github.com/hannasdev/mcp-writing/compare/v1.1.0...v1.1.1) (2026-04-16)
124
+ #### v1.0.0
79
125
 
126
+ > 16 April 2026
80
127
 
81
- ### Bug Fixes
82
-
83
- * use dedicated token for release-please workflow ([#10](https://github.com/hannasdev/mcp-writing/issues/10)) ([6167a59](https://github.com/hannasdev/mcp-writing/commit/6167a598999c173ba04bcdc61223259449e1cf24))
84
-
85
-
86
- ### Miscellaneous Chores
87
-
88
- * fix lint in MCP validation scripts ([2b2385e](https://github.com/hannasdev/mcp-writing/commit/2b2385e3eddd8fd30716d0f72dfa6346ec2d6e5f))
89
- * include chore commits in release automation ([5a28f27](https://github.com/hannasdev/mcp-writing/commit/5a28f277d1551e35c7fd717836c259badbf8a1d9))
90
- * include chore commits in release-please ([c437850](https://github.com/hannasdev/mcp-writing/commit/c4378501ee7dc29d582ce78bc1d227927e719810))
91
- * keep reusable MCP validation scripts ([65f44cb](https://github.com/hannasdev/mcp-writing/commit/65f44cb730176aa4b340c42685dccda05a6725e6))
92
- * keep reusable MCP validation scripts ([9d4181e](https://github.com/hannasdev/mcp-writing/commit/9d4181e32d6ba9a76a33659c5cfedfe9cf296619))
93
- * trigger CI for release-please branches ([09e599a](https://github.com/hannasdev/mcp-writing/commit/09e599a399e6b9e039ef2670cfa51a88518dbd56))
94
-
95
- ## [1.1.0](https://github.com/hannasdev/mcp-writing/compare/v1.0.0...v1.1.0) (2026-04-16)
96
-
97
-
98
- ### Features
99
-
100
- * reconcile Scrivener reorders via stable external IDs ([977a1c3](https://github.com/hannasdev/mcp-writing/commit/977a1c3770861b5f8b0dd9ec8bcdcb00ff39d18a))
101
- * stable Scrivener identity and reorder reconciliation ([14c165f](https://github.com/hannasdev/mcp-writing/commit/14c165fd80050c59e162fd35bd84cbd39b767cee))
128
+ - feat: Phase 1 scaffold — core retrieval tools, SQLite index, SSE transport [`e8bdfa0`](https://github.com/hannasdev/mcp-writing/commit/e8bdfa0001696f6bb8b10f4c69917a833ad4bc4d)
129
+ - Extract db.js + sync.js; add unit + integration tests (40/40 pass) [`e129c0b`](https://github.com/hannasdev/mcp-writing/commit/e129c0be6208f731f0f9405133e9f5d88f171951)
130
+ - Add thread link writes and standardize error envelopes [`4f59904`](https://github.com/hannasdev/mcp-writing/commit/4f599044a85dd740cdbc3f9f884e29c1018af4a0)
package/README.md CHANGED
@@ -32,6 +32,21 @@ npm --version # should be 8.0.0 or later
32
32
  git --version # should be installed
33
33
  ```
34
34
 
35
+ ## First-time setup path (recommended)
36
+
37
+ If this is your first time, use this path and skip the advanced/reference sections for now:
38
+
39
+ 1. Follow either **Quick start with Scrivener** or **Running with Docker**.
40
+ 2. Start the server with `npm start`.
41
+ 3. Run **Verify your setup** (`/healthz` and `/sse`).
42
+ 4. Use the MCP `sync` tool once to build the index.
43
+
44
+ After that, come back to:
45
+
46
+ - **Advanced: Native sync format** for custom project layouts
47
+ - **Reference: Available tools** for the full tool catalog
48
+ - **Appendix: Real-world usage scenarios** for workflow ideas
49
+
35
50
  ## Quick start with Scrivener
36
51
 
37
52
  If you write in [Scrivener](https://www.literatureandlatte.com/scrivener), you can seed `mcp-writing` from a Scrivener external-sync export for scene prose, then curate non-draft content directly into the target folder structure.
@@ -51,6 +66,8 @@ The importer:
51
66
  - Converts `Draft/` files to scene sidecars (`.meta.yaml`) with auto-generated `scene_id`, `title`, `part`, `chapter`, and `save_the_cat_beat` fields derived from the filename/structure.
52
67
  - Skips beat-marker files (`-Setup-`, `-Catalyst-`, etc.), chapter-intro files, epigraphs, and trashed files.
53
68
 
69
+ Important: `sync` does not run this import step for you. If your source is a raw Scrivener `Draft/` export, run `scripts/import.js` first so scene files get `scene_id` metadata before indexing.
70
+
54
71
  Non-draft content is not inferred from `Notes/`. Put it directly into the target sync dir using the `world/` folder conventions described below.
55
72
 
56
73
  ### 3. Start the server
@@ -61,7 +78,7 @@ WRITING_SYNC_DIR=/path/to/sync-dir DB_PATH=./writing.db npm start
61
78
 
62
79
  You should see:
63
80
 
64
- ```
81
+ ```sh
65
82
  Listening on port 3000
66
83
  Sync dir: /path/to/sync-dir
67
84
  Database: ./writing.db
@@ -79,7 +96,7 @@ Exits non-zero if any errors are found. Warnings (e.g. `UNKNOWN_KEY`) are inform
79
96
 
80
97
  ---
81
98
 
82
- ## Native sync format
99
+ ## Advanced: Native sync format
83
100
 
84
101
  For projects not starting from a Scrivener export, place plain `.md` files in the sync folder directly. Metadata lives in a YAML frontmatter block.
85
102
 
@@ -177,7 +194,7 @@ Recommended workflow:
177
194
 
178
195
  ---
179
196
 
180
- ## Real-world usage scenarios
197
+ ## Appendix: Real-world usage scenarios
181
198
 
182
199
  The tool list is useful as reference. These example workflows show how people actually use `mcp-writing` while drafting and revising.
183
200
 
@@ -227,7 +244,7 @@ Outcome: you get AI speed with explicit approval and recoverable history for eve
227
244
 
228
245
  ---
229
246
 
230
- ## Available tools
247
+ ## Reference: Available tools
231
248
 
232
249
  | Tool | Description |
233
250
  | --- | --- |
@@ -235,7 +252,7 @@ Outcome: you get AI speed with explicit approval and recoverable history for eve
235
252
  | `find_scenes` | Filter scenes by character, beat, tag, part, chapter, or POV |
236
253
  | `get_scene_prose` | Load the full prose for a specific scene |
237
254
  | `get_chapter_prose` | Load all prose for a chapter |
238
- | `get_runtime_config` | Show the active sync dir, DB path, and runtime capabilities |
255
+ | `get_runtime_config` | Show active paths/capabilities plus runtime warnings and setup recommendations |
239
256
  | `get_arc` | Ordered scene metadata for all scenes involving a character |
240
257
  | `list_characters` | All characters, optionally filtered by project or universe |
241
258
  | `get_character_sheet` | Full character metadata, traits, notes, and support notes |
@@ -294,6 +311,99 @@ Then register in your OpenClaw config:
294
311
  }
295
312
  ```
296
313
 
314
+ <details>
315
+ <summary>Advanced OpenClaw / Docker integration notes</summary>
316
+
317
+ ### OpenClaw / Docker integration notes
318
+
319
+ When `mcp-writing` runs behind OpenClaw (or any Docker MCP gateway), these details prevent common runtime failures.
320
+
321
+ #### Required environment and mounts
322
+
323
+ - Set `WRITING_SYNC_DIR=/sync`
324
+ - Set `DB_PATH=/data/writing.db`
325
+ - Mount your manuscript sync repo to `/sync`
326
+ - Mount a persistent path for SQLite data at `/data`
327
+
328
+ If `/sync` contains raw Scrivener external-sync output, run the importer once before normal `sync` usage:
329
+
330
+ ```sh
331
+ node scripts/import.js /path/to/scrivener-export /sync --project my-novel
332
+ ```
333
+
334
+ `sync` indexes files that already contain scene metadata. It does not convert Scrivener `Draft/` filenames into scene sidecars by itself.
335
+
336
+ #### Git ownership trust for mounted repos
337
+
338
+ If host and container ownership differ, git can fail with:
339
+
340
+ - `fatal: detected dubious ownership in repository`
341
+
342
+ Mark the mounted repo path as safe in the container image:
343
+
344
+ ```sh
345
+ git config --system --add safe.directory /sync
346
+ ```
347
+
348
+ #### SSH transport hardening
349
+
350
+ For private remotes, mount SSH materials read-only and enforce strict host checks:
351
+
352
+ - Auth key for fetch/pull/push
353
+ - `known_hosts` with GitHub host key
354
+ - `StrictHostKeyChecking=yes`
355
+
356
+ Example:
357
+
358
+ ```sh
359
+ export GIT_SSH_COMMAND="ssh -i /root/.ssh/id_ed25519 -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes -o UserKnownHostsFile=/root/.ssh/known_hosts"
360
+ ```
361
+
362
+ #### Separate auth and signing keys
363
+
364
+ Use dedicated keys for transport and signing:
365
+
366
+ - Auth key: repository transport (`fetch` / `pull` / `push`)
367
+ - Signing key: commit/tag signatures
368
+
369
+ Recommended git config:
370
+
371
+ ```sh
372
+ git config gpg.format ssh
373
+ git config user.signingkey /root/.ssh/id_ed25519_signing
374
+ git config commit.gpgsign true
375
+ git config pull.ff only
376
+ ```
377
+
378
+ #### Git identity and GitHub email privacy
379
+
380
+ If GitHub email privacy is enabled, pushes can fail unless `user.email` is a GitHub noreply address:
381
+
382
+ ```sh
383
+ git config user.name "Edda"
384
+ git config user.email "<id>+<username>@users.noreply.github.com"
385
+ ```
386
+
387
+ #### Branch safety for automation
388
+
389
+ For bot-driven edits, prefer branch-per-change flow:
390
+
391
+ - Push to `edda/*` or `bot/*`
392
+ - Merge via pull request
393
+ - Protect `main` from direct automation pushes
394
+
395
+ #### Quick validation
396
+
397
+ ```sh
398
+ ssh -T git@github.com
399
+ git -C /sync fetch origin
400
+ git -C /sync pull --ff-only
401
+ ```
402
+
403
+ Then create and push a signed smoke commit on a temporary branch.
404
+
405
+ </details>
406
+
297
407
  ## Running locally
298
408
 
299
409
  ```sh
@@ -335,23 +445,50 @@ Unit tests use an in-memory SQLite database and temporary directories — no ser
335
445
 
336
446
  For real projects, keep your manuscript sync folder outside this tool repository and point `WRITING_SYNC_DIR` at that external path.
337
447
 
448
+ ## Release automation
449
+
450
+ This repository uses a `release-it` workflow (modeled after `n8n-nodes-bambulab`) instead of Release Please.
451
+
452
+ How it works:
453
+
454
+ 1. A PR is merged into `main`.
455
+ 2. `.github/workflows/release.yml` runs on that push.
456
+ 3. The workflow infers version bump type from commits since last tag:
457
+ - `BREAKING CHANGE` or `!:` -> major
458
+ - `feat:` -> minor
459
+ - everything else -> patch
460
+ 4. `release-it` creates a `Release x.y.z` commit and `vx.y.z` tag.
461
+ 5. Tag push triggers `.github/workflows/publish.yml` to publish to npm.
462
+
463
+ Required setup:
464
+
465
+ - Repository secret: `RELEASE_TOKEN` (PAT with repository write access)
466
+ - Branch rules must allow this actor to push release commit/tag (for PR-only protection, configure a bypass actor for the token owner)
467
+ - Repository URL in `package.json` must remain valid for npm provenance
468
+
469
+ Local dry-run (optional):
470
+
471
+ ```sh
472
+ npm run release -- --ci --dry-run
473
+ ```
474
+
338
475
  ## Troubleshooting
339
476
 
340
477
  ### "Module not found: sqlite" or "Database support not available"
341
478
 
342
- **Cause:** Node.js version is below 22.6.0 or the `--experimental-sqlite` flag was not passed.
479
+ Your Node.js version is too old, or SQLite support was not started with the required flag.
343
480
 
344
- **Solution:**
345
- 1. Check your Node.js version: `node --version` (should be v22.6.0+)
346
- 2. Update Node.js if needed: use nvm, homebrew, or download from nodejs.org
347
- 3. Restart with `npm start` (which includes the flag automatically)
481
+ Fix:
482
+
483
+ 1. Run `node --version` and confirm v22.6.0 or newer.
484
+ 2. Upgrade Node.js if needed.
485
+ 3. Restart with `npm start` (the script already includes `--experimental-sqlite`).
348
486
 
349
487
  ### "EADDRINUSE: address already in use :::3000"
350
488
 
351
- **Cause:** Port 3000 is already in use by another application.
489
+ Port 3000 is already in use.
352
490
 
353
- **Solution:**
354
- Use a different port:
491
+ Fix: start on a different port.
355
492
 
356
493
  ```sh
357
494
  HTTP_PORT=3001 WRITING_SYNC_DIR=./my-manuscript DB_PATH=./writing.db npm start
@@ -361,10 +498,9 @@ Then update your MCP client config to use `http://localhost:3001/sse`.
361
498
 
362
499
  ### "ENOENT: no such file or directory, open './writing.db'"
363
500
 
364
- **Cause:** The directory for `DB_PATH` does not exist.
501
+ The directory for `DB_PATH` does not exist.
365
502
 
366
- **Solution:**
367
- Create the directory first:
503
+ Fix: create the directory first.
368
504
 
369
505
  ```sh
370
506
  mkdir -p $(dirname ./writing.db) # if using a subdirectory
@@ -379,34 +515,66 @@ WRITING_SYNC_DIR=~/my-manuscript DB_PATH=~/writing-data/writing.db npm start
379
515
 
380
516
  ### "Sync dir not found: ./my-manuscript"
381
517
 
382
- **Cause:** The `WRITING_SYNC_DIR` path does not exist.
518
+ The `WRITING_SYNC_DIR` path does not exist.
383
519
 
384
- **Solution:**
385
- Create the sync folder first:
520
+ Fix: create it (or point to an existing sync folder).
386
521
 
387
522
  ```sh
388
523
  mkdir -p ./my-manuscript/projects/my-novel
389
524
  WRITING_SYNC_DIR=./my-manuscript DB_PATH=./writing.db npm start
390
525
  ```
391
526
 
392
- Or point to an existing folder where you've already placed scene files.
393
-
394
527
  ### "Import failed: unrecognized format"
395
528
 
396
- **Cause:** The Scrivener export format was not plain text (`.txt`) or the folder structure is unexpected.
529
+ Scrivener export is not plain text (`.txt`) or folder layout is unexpected.
530
+
531
+ Fix:
397
532
 
398
- **Solution:**
399
533
  1. In Scrivener, re-export with **File → Sync → With External Folder**
400
534
  2. Ensure the format is set to **Plain text** (not RTF or .docx)
401
535
  3. Verify the export folder has a `Draft/` subdirectory with `.txt` files
402
536
  4. Try the import again: `node scripts/import.js ~/my-novel-txt /path/to/sync-dir --project my-novel`
403
537
 
538
+ ### "OpenClaw can read tools, but scene indexing is empty or incomplete"
539
+
540
+ You are likely running `sync` on raw Scrivener `Draft/` output that has not been imported yet.
541
+
542
+ Fix:
543
+
544
+ 1. Run importer once to create scene metadata sidecars:
545
+
546
+ ```sh
547
+ node scripts/import.js /path/to/scrivener-export /path/to/sync-dir --project my-novel
548
+ ```
549
+
550
+ 2. Restart the service (if needed), then call `sync` again.
551
+
552
+ Note: importer behavior is Draft-aware (`<source>/Draft` if present, else source root), but plain `sync` only indexes already-normalized scene files.
553
+
554
+ ### "Write access to repository denied" (or git push/pull fails in container)
555
+
556
+ Your container can start and read files, but cannot write metadata, create snapshots, or push branches.
557
+
558
+ Fix:
559
+
560
+ 1. Check runtime diagnostics via `get_runtime_config`:
561
+ - `sync_dir_writable` must be `true`
562
+ - `runtime_warnings` should be empty for normal editing flows
563
+ 2. Ensure `/sync` is mounted read-write (no `:ro`) and owned by the container user.
564
+ 3. For mounted git repos with UID mismatch, mark safe directory:
565
+
566
+ ```sh
567
+ git config --system --add safe.directory /sync
568
+ ```
569
+
570
+ 4. Verify SSH key has write access to the remote and `known_hosts` is mounted.
571
+ 5. Prefer branch-per-change workflow (`bot/*` or `edda/*`) if `main` is protected.
572
+
404
573
  ### Tests fail after updating Node.js
405
574
 
406
- **Cause:** SQLite module cache may be stale.
575
+ Local install state may be stale after the Node.js change.
407
576
 
408
- **Solution:**
409
- Clear npm cache and reinstall:
577
+ Fix: reinstall dependencies.
410
578
 
411
579
  ```sh
412
580
  rm -rf node_modules package-lock.json
package/index.js CHANGED
@@ -252,6 +252,43 @@ function generateProposalId() {
252
252
  return `proposal-${nextProposalId++}`;
253
253
  }
254
254
 
255
+ function getRuntimeDiagnostics() {
256
+ const warnings = [];
257
+ const recommendations = [];
258
+
259
+ if (!SYNC_DIR_WRITABLE) {
260
+ warnings.push("SYNC_DIR_READ_ONLY: sync dir is read-only; metadata write-back and prose editing tools are unavailable.");
261
+ recommendations.push("Mount WRITING_SYNC_DIR with write access (avoid read-only mounts like ':ro').");
262
+ recommendations.push("If running in Docker/OpenClaw, verify volume ownership and permissions for the container user.");
263
+ }
264
+
265
+ if (!GIT_AVAILABLE) {
266
+ warnings.push("GIT_NOT_FOUND: git is not available on PATH; snapshot/edit tools are unavailable.");
267
+ recommendations.push("Install git in the runtime image/environment.");
268
+ }
269
+
270
+ if (GIT_AVAILABLE && SYNC_DIR_WRITABLE && !GIT_ENABLED) {
271
+ warnings.push("GIT_DISABLED: git is available but repository snapshot tools are not active.");
272
+ recommendations.push("Ensure WRITING_SYNC_DIR points to a writable git repository root, or allow mcp-writing to initialize one.");
273
+ }
274
+
275
+ if (GIT_AVAILABLE && !SYNC_DIR_WRITABLE) {
276
+ recommendations.push("If git reports 'dubious ownership' for mounted repos, add: git config --system --add safe.directory /sync");
277
+ }
278
+
279
+ recommendations.push("If indexing finds many files without scene_id, run scripts/import.js first for Scrivener Draft exports, then run sync.");
280
+
281
+ return { warnings, recommendations };
282
+ }
283
+
284
+ const RUNTIME_DIAGNOSTICS = getRuntimeDiagnostics();
285
+ if (RUNTIME_DIAGNOSTICS.warnings.length) {
286
+ process.stderr.write(`[mcp-writing] Runtime diagnostics:\n`);
287
+ for (const line of RUNTIME_DIAGNOSTICS.warnings) {
288
+ process.stderr.write(`[mcp-writing] - ${line}\n`);
289
+ }
290
+ }
291
+
255
292
  // Run sync on startup
256
293
  syncAll(db, SYNC_DIR, { writable: SYNC_DIR_WRITABLE });
257
294
 
@@ -267,6 +304,7 @@ function createMcpServer() {
267
304
  const parts = [`Sync complete. ${result.indexed} scenes indexed. ${result.staleMarked} scenes marked stale.`];
268
305
  if (result.sidecarsMigrated) parts.push(`${result.sidecarsMigrated} sidecar(s) auto-generated from frontmatter.`);
269
306
  if (result.skipped) parts.push(`${result.skipped} file(s) skipped (no scene_id).`);
307
+ if (result.skipped) parts.push(`Tip: for raw Scrivener Draft exports, run scripts/import.js first, then run sync again.`);
270
308
  if (result.warnings.length) parts.push(`\n⚠️ Warnings:\n` + result.warnings.map(w => `- ${w}`).join("\n"));
271
309
  return { content: [{ type: "text", text: parts.join(" ") }] };
272
310
  });
@@ -284,6 +322,8 @@ function createMcpServer() {
284
322
  git_available: GIT_AVAILABLE,
285
323
  git_enabled: GIT_ENABLED,
286
324
  http_port: HTTP_PORT,
325
+ runtime_warnings: RUNTIME_DIAGNOSTICS.warnings,
326
+ setup_recommendations: RUNTIME_DIAGNOSTICS.recommendations,
287
327
  });
288
328
  }
289
329
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanna84/mcp-writing",
3
- "version": "1.3.8",
3
+ "version": "1.4.1",
4
4
  "description": "MCP service for AI-assisted reasoning and editing on long-form fiction projects",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -20,6 +20,7 @@
20
20
  "scripts": {
21
21
  "start": "node --experimental-sqlite index.js",
22
22
  "new:entity": "node scripts/new-world-entity.js",
23
+ "release": "release-it",
23
24
  "lint": "eslint index.js db.js sync.js metadata-lint.js scripts/",
24
25
  "lint:metadata": "node scripts/lint-metadata.mjs",
25
26
  "test:unit": "node --experimental-sqlite --test test/unit.test.mjs",
@@ -48,7 +49,9 @@
48
49
  },
49
50
  "devDependencies": {
50
51
  "@eslint/js": "^10.0.1",
52
+ "auto-changelog": "^2.5.0",
51
53
  "eslint": "^10.2.0",
52
- "globals": "^17.5.0"
54
+ "globals": "^17.5.0",
55
+ "release-it": "^20.0.0"
53
56
  }
54
57
  }