openwriter 0.8.1 → 0.8.3
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/dist/client/assets/{index-D0TNu7yx.js → index-B10tGLgo.js} +68 -68
- package/dist/client/assets/index-Cd7iUO_s.css +1 -0
- package/dist/client/index.html +2 -2
- package/dist/plugins/publish/dist/index.js +64 -0
- package/dist/plugins/publish/dist/newsletter-tools.js +31 -1
- package/dist/server/billing-routes.js +69 -0
- package/dist/server/index.js +3 -0
- package/dist/server/mcp.js +5 -0
- package/dist/server/state.js +4 -1
- package/package.json +96 -96
- package/skill/SKILL.md +32 -4
- package/dist/client/assets/index-Dze14Bgb.css +0 -1
package/package.json
CHANGED
|
@@ -1,96 +1,96 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "openwriter",
|
|
3
|
-
"version": "0.8.
|
|
4
|
-
"description": "The open-source writing surface for AI agents. Markdown-native editor with pending change review — your agent writes, you accept or reject.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"license": "MIT",
|
|
7
|
-
"author": "Travis Steward",
|
|
8
|
-
"repository": {
|
|
9
|
-
"type": "git",
|
|
10
|
-
"url": "https://github.com/travsteward/openwriter.git"
|
|
11
|
-
},
|
|
12
|
-
"homepage": "https://github.com/travsteward/openwriter",
|
|
13
|
-
"bugs": "https://github.com/travsteward/openwriter/issues",
|
|
14
|
-
"keywords": [
|
|
15
|
-
"editor",
|
|
16
|
-
"tiptap",
|
|
17
|
-
"mcp",
|
|
18
|
-
"ai",
|
|
19
|
-
"writing",
|
|
20
|
-
"agent",
|
|
21
|
-
"local-first",
|
|
22
|
-
"markdown",
|
|
23
|
-
"rich-text",
|
|
24
|
-
"human-agent-collaboration"
|
|
25
|
-
],
|
|
26
|
-
"bin": {
|
|
27
|
-
"openwriter": "./dist/bin/pad.js"
|
|
28
|
-
},
|
|
29
|
-
"exports": {
|
|
30
|
-
".": "./dist/bin/pad.js",
|
|
31
|
-
"./plugin-types": "./dist/server/plugin-types.js"
|
|
32
|
-
},
|
|
33
|
-
"scripts": {
|
|
34
|
-
"build": "vite build && tsc -p tsconfig.server.json",
|
|
35
|
-
"prepublishOnly": "node scripts/prepublish.cjs",
|
|
36
|
-
"preview": "node dist/bin/pad.js",
|
|
37
|
-
"lint": "eslint src server bin --ext .ts,.tsx"
|
|
38
|
-
},
|
|
39
|
-
"dependencies": {
|
|
40
|
-
"@google/genai": "^1.42.0",
|
|
41
|
-
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
42
|
-
"@tiptap/core": "^3.0.0",
|
|
43
|
-
"@tiptap/extension-code-block-lowlight": "^3.19.0",
|
|
44
|
-
"@tiptap/extension-highlight": "^3.19.0",
|
|
45
|
-
"@tiptap/extension-image": "^3.19.0",
|
|
46
|
-
"@tiptap/extension-link": "^3.19.0",
|
|
47
|
-
"@tiptap/extension-placeholder": "^3.0.0",
|
|
48
|
-
"@tiptap/extension-subscript": "^3.19.0",
|
|
49
|
-
"@tiptap/extension-superscript": "^3.19.0",
|
|
50
|
-
"@tiptap/extension-table": "^3.19.0",
|
|
51
|
-
"@tiptap/extension-task-item": "^3.19.0",
|
|
52
|
-
"@tiptap/extension-task-list": "^3.19.0",
|
|
53
|
-
"@tiptap/extension-text-style": "^3.0.0",
|
|
54
|
-
"@tiptap/extension-typography": "^3.19.0",
|
|
55
|
-
"@tiptap/extension-underline": "^3.0.0",
|
|
56
|
-
"@tiptap/extension-unique-id": "^3.0.0",
|
|
57
|
-
"@tiptap/pm": "^3.0.0",
|
|
58
|
-
"@tiptap/react": "^3.0.0",
|
|
59
|
-
"@tiptap/starter-kit": "^3.0.0",
|
|
60
|
-
"@turbodocx/html-to-docx": "^1.20.1",
|
|
61
|
-
"@types/multer": "^2.0.0",
|
|
62
|
-
"@xdevplatform/xdk": "^0.4.0",
|
|
63
|
-
"express": "^4.21.0",
|
|
64
|
-
"gray-matter": "^4.0.3",
|
|
65
|
-
"lowlight": "^3.3.0",
|
|
66
|
-
"markdown-it": "^14.1.1",
|
|
67
|
-
"markdown-it-ins": "^4.0.0",
|
|
68
|
-
"markdown-it-mark": "^4.0.0",
|
|
69
|
-
"markdown-it-sub": "^2.0.0",
|
|
70
|
-
"markdown-it-sup": "^2.0.0",
|
|
71
|
-
"multer": "^2.0.2",
|
|
72
|
-
"open": "^10.1.0",
|
|
73
|
-
"react": "^18.3.1",
|
|
74
|
-
"react-dom": "^18.3.1",
|
|
75
|
-
"trash": "^10.1.0",
|
|
76
|
-
"twitter-text": "^3.1.0",
|
|
77
|
-
"ws": "^8.18.0",
|
|
78
|
-
"zod": "^3.25.76"
|
|
79
|
-
},
|
|
80
|
-
"devDependencies": {
|
|
81
|
-
"@types/express": "^5.0.0",
|
|
82
|
-
"@types/markdown-it": "^14.1.2",
|
|
83
|
-
"@types/react": "^18.3.0",
|
|
84
|
-
"@types/react-dom": "^18.3.0",
|
|
85
|
-
"@types/twitter-text": "^3.1.10",
|
|
86
|
-
"@types/ws": "^8.5.0",
|
|
87
|
-
"@vitejs/plugin-react": "^4.3.0",
|
|
88
|
-
"typescript": "^5.6.0",
|
|
89
|
-
"vite": "^6.0.0"
|
|
90
|
-
},
|
|
91
|
-
"files": [
|
|
92
|
-
"dist/",
|
|
93
|
-
"skill/",
|
|
94
|
-
"package.json"
|
|
95
|
-
]
|
|
96
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "openwriter",
|
|
3
|
+
"version": "0.8.3",
|
|
4
|
+
"description": "The open-source writing surface for AI agents. Markdown-native editor with pending change review — your agent writes, you accept or reject.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Travis Steward",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/travsteward/openwriter.git"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/travsteward/openwriter",
|
|
13
|
+
"bugs": "https://github.com/travsteward/openwriter/issues",
|
|
14
|
+
"keywords": [
|
|
15
|
+
"editor",
|
|
16
|
+
"tiptap",
|
|
17
|
+
"mcp",
|
|
18
|
+
"ai",
|
|
19
|
+
"writing",
|
|
20
|
+
"agent",
|
|
21
|
+
"local-first",
|
|
22
|
+
"markdown",
|
|
23
|
+
"rich-text",
|
|
24
|
+
"human-agent-collaboration"
|
|
25
|
+
],
|
|
26
|
+
"bin": {
|
|
27
|
+
"openwriter": "./dist/bin/pad.js"
|
|
28
|
+
},
|
|
29
|
+
"exports": {
|
|
30
|
+
".": "./dist/bin/pad.js",
|
|
31
|
+
"./plugin-types": "./dist/server/plugin-types.js"
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "vite build && tsc -p tsconfig.server.json",
|
|
35
|
+
"prepublishOnly": "node scripts/prepublish.cjs",
|
|
36
|
+
"preview": "node dist/bin/pad.js",
|
|
37
|
+
"lint": "eslint src server bin --ext .ts,.tsx"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@google/genai": "^1.42.0",
|
|
41
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
42
|
+
"@tiptap/core": "^3.0.0",
|
|
43
|
+
"@tiptap/extension-code-block-lowlight": "^3.19.0",
|
|
44
|
+
"@tiptap/extension-highlight": "^3.19.0",
|
|
45
|
+
"@tiptap/extension-image": "^3.19.0",
|
|
46
|
+
"@tiptap/extension-link": "^3.19.0",
|
|
47
|
+
"@tiptap/extension-placeholder": "^3.0.0",
|
|
48
|
+
"@tiptap/extension-subscript": "^3.19.0",
|
|
49
|
+
"@tiptap/extension-superscript": "^3.19.0",
|
|
50
|
+
"@tiptap/extension-table": "^3.19.0",
|
|
51
|
+
"@tiptap/extension-task-item": "^3.19.0",
|
|
52
|
+
"@tiptap/extension-task-list": "^3.19.0",
|
|
53
|
+
"@tiptap/extension-text-style": "^3.0.0",
|
|
54
|
+
"@tiptap/extension-typography": "^3.19.0",
|
|
55
|
+
"@tiptap/extension-underline": "^3.0.0",
|
|
56
|
+
"@tiptap/extension-unique-id": "^3.0.0",
|
|
57
|
+
"@tiptap/pm": "^3.0.0",
|
|
58
|
+
"@tiptap/react": "^3.0.0",
|
|
59
|
+
"@tiptap/starter-kit": "^3.0.0",
|
|
60
|
+
"@turbodocx/html-to-docx": "^1.20.1",
|
|
61
|
+
"@types/multer": "^2.0.0",
|
|
62
|
+
"@xdevplatform/xdk": "^0.4.0",
|
|
63
|
+
"express": "^4.21.0",
|
|
64
|
+
"gray-matter": "^4.0.3",
|
|
65
|
+
"lowlight": "^3.3.0",
|
|
66
|
+
"markdown-it": "^14.1.1",
|
|
67
|
+
"markdown-it-ins": "^4.0.0",
|
|
68
|
+
"markdown-it-mark": "^4.0.0",
|
|
69
|
+
"markdown-it-sub": "^2.0.0",
|
|
70
|
+
"markdown-it-sup": "^2.0.0",
|
|
71
|
+
"multer": "^2.0.2",
|
|
72
|
+
"open": "^10.1.0",
|
|
73
|
+
"react": "^18.3.1",
|
|
74
|
+
"react-dom": "^18.3.1",
|
|
75
|
+
"trash": "^10.1.0",
|
|
76
|
+
"twitter-text": "^3.1.0",
|
|
77
|
+
"ws": "^8.18.0",
|
|
78
|
+
"zod": "^3.25.76"
|
|
79
|
+
},
|
|
80
|
+
"devDependencies": {
|
|
81
|
+
"@types/express": "^5.0.0",
|
|
82
|
+
"@types/markdown-it": "^14.1.2",
|
|
83
|
+
"@types/react": "^18.3.0",
|
|
84
|
+
"@types/react-dom": "^18.3.0",
|
|
85
|
+
"@types/twitter-text": "^3.1.10",
|
|
86
|
+
"@types/ws": "^8.5.0",
|
|
87
|
+
"@vitejs/plugin-react": "^4.3.0",
|
|
88
|
+
"typescript": "^5.6.0",
|
|
89
|
+
"vite": "^6.0.0"
|
|
90
|
+
},
|
|
91
|
+
"files": [
|
|
92
|
+
"dist/",
|
|
93
|
+
"skill/",
|
|
94
|
+
"package.json"
|
|
95
|
+
]
|
|
96
|
+
}
|
package/skill/SKILL.md
CHANGED
|
@@ -16,7 +16,7 @@ description: |
|
|
|
16
16
|
Requires: OpenWriter MCP server configured. Browser UI at localhost:5050.
|
|
17
17
|
metadata:
|
|
18
18
|
author: travsteward
|
|
19
|
-
version: "0.4.
|
|
19
|
+
version: "0.4.1"
|
|
20
20
|
repository: https://github.com/travsteward/openwriter
|
|
21
21
|
license: MIT
|
|
22
22
|
---
|
|
@@ -30,6 +30,7 @@ You are a writing collaborator. You read documents and make edits **exclusively
|
|
|
30
30
|
1. **ALWAYS write content in the editor, never in the terminal.** OpenWriter is a collaborative writing surface. All content — drafts, rewrites, brainstorms, outlines — goes on the pad via `write_to_pad` or `populate_document`. Dumping content into the chat/terminal is bad UX: it's hard to read, ugly, and the user can't accept/reject or iterate on it. If you're generating text the user will read, it goes in the editor.
|
|
31
31
|
2. **The terminal is for discussion only.** Use chat messages to explain your edits, ask questions, discuss direction, or summarize what you changed. Never use it as the writing surface.
|
|
32
32
|
3. **Name every document.** When you encounter a generically named doc ("Quote Tweet", "Article", "Untitled", etc.), rename it based on its content before proceeding. Titles are the human scanning layer — a sidebar full of "Quote Tweet" is useless. Use `rename_item` with the docId. Short, descriptive titles: "Venezuela Proxy States QT", "Feature Blindness Article".
|
|
33
|
+
4. **Metadata first.** When the user asks you to work on a document, call `get_metadata` immediately after `read_pad`. Tweet docs store the parent URL in `tweetContext.url`, article docs store context in `articleContext`. **Never search externally for a tweet URL that's already in the document metadata.** This prevents wasting paid API calls on information you already have.
|
|
33
34
|
|
|
34
35
|
## Setup — Which Path?
|
|
35
36
|
|
|
@@ -249,10 +250,13 @@ This eliminates the need for separate `create_workspace`, `create_container`, an
|
|
|
249
250
|
```
|
|
250
251
|
1. get_pad_status → check pendingChanges and userSignaledReview
|
|
251
252
|
2. read_pad → get full document with node IDs + docId
|
|
252
|
-
3.
|
|
253
|
-
4.
|
|
253
|
+
3. get_metadata → check tweetContext/articleContext for URLs, mode, tags
|
|
254
|
+
4. write_to_pad({ docId: "a1b2c3d4", changes: [...] })
|
|
255
|
+
5. Wait → user accepts/rejects in browser
|
|
254
256
|
```
|
|
255
257
|
|
|
258
|
+
**For tweet/article docs:** step 3 gives you the parent tweet URL (in `tweetContext.url`) and mode (`reply`/`quote`/`tweet`). Use this URL with fxtwitter to read the parent tweet for free — never search externally for it.
|
|
259
|
+
|
|
256
260
|
### Multi-document
|
|
257
261
|
|
|
258
262
|
```
|
|
@@ -331,7 +335,30 @@ OpenWriter doubles as a tweet compose surface. When `tweetContext` is set in a d
|
|
|
331
335
|
|
|
332
336
|
The view activates automatically when `tweetContext` is present — no manual toggle needed. Documents are auto-tagged `"x"` in the sidebar for discoverability.
|
|
333
337
|
|
|
334
|
-
###
|
|
338
|
+
### Working on an existing tweet document
|
|
339
|
+
|
|
340
|
+
When the user asks you to work on a tweet doc, follow this exact sequence:
|
|
341
|
+
|
|
342
|
+
```
|
|
343
|
+
1. read_pad → get content + node IDs + docId
|
|
344
|
+
2. get_metadata → get tweetContext (url, mode), tags
|
|
345
|
+
3. Extract tweet URL → parse username + tweet ID from tweetContext.url
|
|
346
|
+
4. WebFetch fxtwitter → read the parent tweet for FREE
|
|
347
|
+
5. Check workspaces → find relevant reference docs for context
|
|
348
|
+
6. Write → now you have everything, edit the pad
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
**Step 3-4 in detail:** Parse the URL from `tweetContext.url` (e.g. `https://x.com/HustleBitch_/status/2033641235739496554`) → extract username and ID → fetch via fxtwitter:
|
|
352
|
+
|
|
353
|
+
```
|
|
354
|
+
WebFetch: https://api.fxtwitter.com/{username}/status/{tweet_id}
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
This returns full text, metrics, media, quoted tweets — all for FREE. **Never use paid X API search to find a tweet that's already in the document metadata.**
|
|
358
|
+
|
|
359
|
+
**Step 5:** If the tweet references concepts the user has written about (dimorphism, territory, frame, etc.), check their workspaces via `list_workspaces` → `get_workspace_structure` → `read_pad` on relevant reference docs. This gives you the user's framework to write from, not generic knowledge.
|
|
360
|
+
|
|
361
|
+
### Reading the parent tweet (when creating new tweet docs)
|
|
335
362
|
|
|
336
363
|
Use the x-reader skill or fxtwitter API to fetch tweet data before setting up:
|
|
337
364
|
|
|
@@ -551,6 +578,7 @@ Requires authentication via `request_login_code` + `verify_login`. All publish t
|
|
|
551
578
|
| `import_subscribers` | `file?`, `csv_text?` | Bulk import from CSV (auto-detects ConvertKit, Mailchimp, Substack, Beehiiv formats) |
|
|
552
579
|
| `list_newsletter_issues` | `limit?` | List past sends with open/click stats — returns issue IDs |
|
|
553
580
|
| `get_newsletter_analytics` | `issue_id` | Detailed drill-down: delivery stats, per-subscriber events, recipient list |
|
|
581
|
+
| `get_subscribe_embed` | *(none)* | Get public subscribe URL + HTML/JS embed snippets for signup forms on external sites |
|
|
554
582
|
|
|
555
583
|
**Subscriber selection** — `send_newsletter` supports targeting:
|
|
556
584
|
- **All subscribers** (default) — omit both params
|