@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.
- package/CHANGELOG.md +84 -55
- package/README.md +194 -26
- package/index.js +40 -0
- package/package.json +5 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,101 +1,130 @@
|
|
|
1
|
-
|
|
1
|
+
### Changelog
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
7
|
+
#### [v1.4.1](https://github.com/hannasdev/mcp-writing/compare/v1.4.0...v1.4.1)
|
|
7
8
|
|
|
8
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
23
|
+
#### [v1.3.8](https://github.com/hannasdev/mcp-writing/compare/v1.3.7...v1.3.8)
|
|
16
24
|
|
|
17
|
-
|
|
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
|
-
|
|
30
|
+
#### [v1.3.7](https://github.com/hannasdev/mcp-writing/compare/v1.3.6...v1.3.7)
|
|
21
31
|
|
|
22
|
-
|
|
32
|
+
> 18 April 2026
|
|
23
33
|
|
|
24
|
-
|
|
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
|
-
|
|
40
|
+
> 18 April 2026
|
|
28
41
|
|
|
29
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
54
|
+
#### [v1.3.4](https://github.com/hannasdev/mcp-writing/compare/v1.3.3...v1.3.4)
|
|
37
55
|
|
|
38
|
-
|
|
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
|
-
|
|
61
|
+
#### [v1.3.3](https://github.com/hannasdev/mcp-writing/compare/v1.3.2...v1.3.3)
|
|
42
62
|
|
|
43
|
-
|
|
63
|
+
> 18 April 2026
|
|
44
64
|
|
|
45
|
-
|
|
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
|
-
|
|
70
|
+
> 18 April 2026
|
|
49
71
|
|
|
50
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
91
|
+
#### [v1.2.0](https://github.com/hannasdev/mcp-writing/compare/v1.1.1...v1.2.0)
|
|
63
92
|
|
|
64
|
-
|
|
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
|
-
|
|
98
|
+
#### [v1.1.1](https://github.com/hannasdev/mcp-writing/compare/v1.1.0...v1.1.1)
|
|
68
99
|
|
|
69
|
-
|
|
100
|
+
> 16 April 2026
|
|
70
101
|
|
|
71
|
-
|
|
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
|
-
|
|
113
|
+
> 16 April 2026
|
|
75
114
|
|
|
76
|
-
|
|
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
|
-
|
|
124
|
+
#### v1.0.0
|
|
79
125
|
|
|
126
|
+
> 16 April 2026
|
|
80
127
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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
|
|
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
|
-
|
|
479
|
+
Your Node.js version is too old, or SQLite support was not started with the required flag.
|
|
343
480
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
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
|
-
|
|
489
|
+
Port 3000 is already in use.
|
|
352
490
|
|
|
353
|
-
|
|
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
|
-
|
|
501
|
+
The directory for `DB_PATH` does not exist.
|
|
365
502
|
|
|
366
|
-
|
|
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
|
-
|
|
518
|
+
The `WRITING_SYNC_DIR` path does not exist.
|
|
383
519
|
|
|
384
|
-
|
|
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
|
-
|
|
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
|
-
|
|
575
|
+
Local install state may be stale after the Node.js change.
|
|
407
576
|
|
|
408
|
-
|
|
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
|
+
"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
|
}
|