openwriter 0.16.0 → 0.18.0
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-0ttVnjRp.css +1 -0
- package/dist/client/assets/{index-JMMJM_G_.js → index-BZ7LCzrR.js} +57 -57
- package/dist/client/index.html +2 -2
- package/dist/server/compact.js +28 -2
- package/dist/server/enrichment.js +13 -2
- package/dist/server/export-routes.js +2 -0
- package/dist/server/markdown-parse.js +82 -0
- package/dist/server/markdown-serialize.js +86 -1
- package/dist/server/mcp.js +60 -10
- package/dist/server/node-blocks.js +41 -1
- package/dist/server/state.js +22 -15
- package/dist/server/workspace-tree.js +18 -3
- package/dist/server/workspaces.js +2 -2
- package/package.json +2 -1
- package/skill/SKILL.md +13 -1
- package/skill/agents/openwriter-enrichment-minion.md +3 -10
- package/skill/docs/footnotes.md +178 -0
- package/dist/client/assets/index-CbSQ8xxn.css +0 -1
|
@@ -210,9 +210,9 @@ export function reorderDoc(wsFile, file, afterFile) {
|
|
|
210
210
|
// ============================================================================
|
|
211
211
|
// CONTAINER OPERATIONS
|
|
212
212
|
// ============================================================================
|
|
213
|
-
export function addContainerToWorkspace(wsFile, parentContainerId, name) {
|
|
213
|
+
export function addContainerToWorkspace(wsFile, parentContainerId, name, afterIdentifier) {
|
|
214
214
|
const ws = getWorkspace(wsFile);
|
|
215
|
-
const container = addContainerToTree(ws.root, parentContainerId, name);
|
|
215
|
+
const container = addContainerToTree(ws.root, parentContainerId, name, afterIdentifier ?? null);
|
|
216
216
|
writeWorkspace(wsFile, ws);
|
|
217
217
|
return { workspace: ws, containerId: container.id };
|
|
218
218
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openwriter",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
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
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
"gray-matter": "^4.0.3",
|
|
65
65
|
"lowlight": "^3.3.0",
|
|
66
66
|
"markdown-it": "^14.1.1",
|
|
67
|
+
"markdown-it-footnote": "^4.0.0",
|
|
67
68
|
"markdown-it-ins": "^4.0.0",
|
|
68
69
|
"markdown-it-mark": "^4.0.0",
|
|
69
70
|
"markdown-it-sub": "^2.0.0",
|
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.7.
|
|
19
|
+
version: "0.7.6"
|
|
20
20
|
repository: https://github.com/travsteward/openwriter
|
|
21
21
|
license: MIT
|
|
22
22
|
---
|
|
@@ -303,6 +303,18 @@ When creating **two or more documents together** — a tweet thread saved as sep
|
|
|
303
303
|
- `reply` / `quote` types still require `url`
|
|
304
304
|
- For a **single** document, use `create_document` — don't reach for `declare_writes` just to wrap one entry
|
|
305
305
|
|
|
306
|
+
### Citations & footnotes
|
|
307
|
+
|
|
308
|
+
Long-form writing (especially academic-adjacent nonfiction) uses CommonMark / Pandoc footnote syntax:
|
|
309
|
+
|
|
310
|
+
- **Reference** (inline in prose): `text[^1]` — renders as a superscript chip
|
|
311
|
+
- **Definition** (anywhere in the markdown body): `[^1]: footnote text` — automatically corralled into a "Footnotes" section at end-of-doc on save
|
|
312
|
+
- **Mnemonic labels** allowed: `[^sapolsky2017]` survives round-trip on disk; the editor shows auto-sequential display numbers regardless
|
|
313
|
+
|
|
314
|
+
Just include the syntax in `populate_document` content or `write_to_pad` content — no special tool needed. The parser handles the tokenization, the editor handles the rendering, the serializer enforces the constrained end-of-doc shape.
|
|
315
|
+
|
|
316
|
+
**Scope is per-doc.** Each chapter has its own `[^1]` … `[^N]` numbering; cross-doc references aren't supported at the editor level. Full guide → `docs/footnotes.md`.
|
|
317
|
+
|
|
306
318
|
## Companion Skills (optional)
|
|
307
319
|
|
|
308
320
|
For voice-matched drafting without a custom Author's Voice profile, install the **voice-presets** skill — 5 frames (authority, provocateur, logical, storyteller, business). For an AI-detection pass on output, install **anti-ai**. Both are optional and ship separately from this skill.
|
|
@@ -27,16 +27,9 @@ questions. The main agent dispatched you because the work needs doing.
|
|
|
27
27
|
|
|
28
28
|
Five frontmatter fields that capture each doc's identity in 50–200 tokens:
|
|
29
29
|
|
|
30
|
-
- **logline** —
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
the logline and knows whether to open it.
|
|
34
|
-
**Length: 140-character target, 150-character HARD CAP.** Count characters
|
|
35
|
-
literally before submitting. If your draft is over 150, rewrite it shorter
|
|
36
|
-
— don't submit and hope. Cutting the introductory clause is usually the
|
|
37
|
-
fastest fix ("Master reference for human sexual dimorphism: T-gate
|
|
38
|
-
mechanism, dimorphic traits, contest selection." → drop "Master reference
|
|
39
|
-
for" if you need room).
|
|
30
|
+
- **logline** — précis (non-fiction) or logline (fiction) summarizing the
|
|
31
|
+
content. Under 250 chars. No scaffolding — describe the content itself,
|
|
32
|
+
not the kind of doc it is.
|
|
40
33
|
- **domain** — single classification string. If the workspace declares a
|
|
41
34
|
`vocab` array, the value must come from that list (closed set). If no
|
|
42
35
|
vocab, pick a short durable label (1–3 words, title-case). Stay consistent
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# Footnotes — Author Guide for Agents
|
|
2
|
+
|
|
3
|
+
OpenWriter supports CommonMark / Pandoc footnote syntax for citation-heavy
|
|
4
|
+
long-form writing. The editor renders inline references as superscript
|
|
5
|
+
chips and corrals definitions into an end-of-doc "Footnotes" section.
|
|
6
|
+
|
|
7
|
+
This doc explains how to write footnotes via MCP tools and what to expect
|
|
8
|
+
on disk and in the editor.
|
|
9
|
+
|
|
10
|
+
## The syntax (Pandoc / CommonMark)
|
|
11
|
+
|
|
12
|
+
Two parts:
|
|
13
|
+
|
|
14
|
+
- **Reference** (inline): `text[^N]` — appears in the prose
|
|
15
|
+
- **Definition** (block): `[^N]: footnote text` — appears at end of doc
|
|
16
|
+
|
|
17
|
+
Labels can be numeric or mnemonic:
|
|
18
|
+
|
|
19
|
+
```markdown
|
|
20
|
+
Humans run fixed action patterns[^1] too.
|
|
21
|
+
|
|
22
|
+
Per Sapolsky[^sapolsky2017], stress responses follow a pattern.
|
|
23
|
+
|
|
24
|
+
[^1]: Eibl-Eibesfeldt 1973, replicated and extended by Galati et al. 2003.
|
|
25
|
+
|
|
26
|
+
[^sapolsky2017]: Sapolsky, R. (2017). *Behave*. Penguin Press.
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The author label (`1` or `sapolsky2017`) is what pairs reference to
|
|
30
|
+
definition. **Display numbering is automatic** — the editor's CSS counter
|
|
31
|
+
shows sequential `[1] [2] [3]` regardless of label. Mnemonic labels stay
|
|
32
|
+
on disk for human-readable file diffs.
|
|
33
|
+
|
|
34
|
+
## How to write footnotes from MCP
|
|
35
|
+
|
|
36
|
+
Just include the syntax in your markdown content — no special tool needed.
|
|
37
|
+
|
|
38
|
+
### populate_document (initial draft)
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
populate_document({
|
|
42
|
+
docId: "abc12345",
|
|
43
|
+
content: `# Chapter 1
|
|
44
|
+
|
|
45
|
+
Theory of mind develops late[^1] in non-human primates.
|
|
46
|
+
|
|
47
|
+
[^1]: Premack & Woodruff (1978), Behavioral and Brain Sciences 1: 515–526.
|
|
48
|
+
`
|
|
49
|
+
})
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The parser handles `[^1]` references and `[^1]: ...` definitions. The
|
|
53
|
+
editor renders the reference as a superscript chip and the definition
|
|
54
|
+
inside an end-of-doc "Footnotes" section.
|
|
55
|
+
|
|
56
|
+
### write_to_pad (adding to existing doc)
|
|
57
|
+
|
|
58
|
+
To add a new footnote to existing prose, you have two paths.
|
|
59
|
+
|
|
60
|
+
**Append a new reference + definition together** (recommended):
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
// Step 1: rewrite the paragraph to add the reference
|
|
64
|
+
write_to_pad({
|
|
65
|
+
docId: "abc12345",
|
|
66
|
+
changes: [
|
|
67
|
+
{
|
|
68
|
+
operation: "rewrite",
|
|
69
|
+
nodeId: "para_id",
|
|
70
|
+
content: "The same sentence now with a new claim[^2]."
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
// Step 2: append the definition. If the doc already has a footnoteSection,
|
|
76
|
+
// you can insert the definition inside it via afterNodeId pointing at the
|
|
77
|
+
// last definition. If the doc has no footnotes yet, the parser auto-creates
|
|
78
|
+
// the section when it sees `[^N]: ...` at the end of the markdown body.
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Simpler: just include both the reference and the definition in one
|
|
82
|
+
write_to_pad call**:
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
write_to_pad({
|
|
86
|
+
docId: "abc12345",
|
|
87
|
+
changes: [
|
|
88
|
+
{
|
|
89
|
+
operation: "rewrite",
|
|
90
|
+
nodeId: "para_id",
|
|
91
|
+
content: "Sentence with new claim[^2]."
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
operation: "insert",
|
|
95
|
+
afterNodeId: "end",
|
|
96
|
+
content: "[^2]: Smith et al. (2020), Nature 580: 142–148."
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
})
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The serializer normalizes definitions to the end-of-doc `footnoteSection`
|
|
103
|
+
regardless of where they're inserted in the tree.
|
|
104
|
+
|
|
105
|
+
## What you see in `read_pad`
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
title: My Chapter
|
|
109
|
+
id: abc12345
|
|
110
|
+
words: 423
|
|
111
|
+
pending: 0
|
|
112
|
+
---
|
|
113
|
+
[h1:aa0001] Chapter 1
|
|
114
|
+
[p:bb0002] Theory of mind develops late[^1] in non-human primates.
|
|
115
|
+
[fnsec:cc0003]
|
|
116
|
+
[fndef:dd0004] [^1]: Premack & Woodruff (1978), Behavioral and Brain Sciences 1: 515–526.
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The `[^N]` in the body is the inline reference. `[fnsec:...]` is the
|
|
120
|
+
end-of-doc section. `[fndef:...]` is each definition.
|
|
121
|
+
|
|
122
|
+
## Per-doc scope — important
|
|
123
|
+
|
|
124
|
+
**Footnote labels are local to each doc.** Chapter 3's `[^1]` does not
|
|
125
|
+
refer to Chapter 4's `[^1]`. Each chapter is its own `.md` file with its
|
|
126
|
+
own numbering. Cross-chapter references are not supported at the editor
|
|
127
|
+
level (a future book-export pipeline will handle global numbering at
|
|
128
|
+
typeset time).
|
|
129
|
+
|
|
130
|
+
If the author writes "see Ch 1 note 4" they're writing prose, not a
|
|
131
|
+
cross-doc footnote link.
|
|
132
|
+
|
|
133
|
+
## Multi-paragraph definitions
|
|
134
|
+
|
|
135
|
+
Pandoc allows multi-paragraph footnotes via 4-space-indented continuation:
|
|
136
|
+
|
|
137
|
+
```markdown
|
|
138
|
+
[^1]: First paragraph of the definition.
|
|
139
|
+
|
|
140
|
+
Continuation paragraph, indented 4 spaces.
|
|
141
|
+
|
|
142
|
+
Another continuation.
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
The editor preserves the multi-paragraph structure inside the definition.
|
|
146
|
+
Use this for footnotes that need substantial explanation (lengthy
|
|
147
|
+
methodology notes, multi-source citations, etc.).
|
|
148
|
+
|
|
149
|
+
## What's NOT supported (yet)
|
|
150
|
+
|
|
151
|
+
- **Cross-doc footnote references.** Each doc has its own numbering.
|
|
152
|
+
- **Bibliography auto-generation.** Authors manage citation text inline.
|
|
153
|
+
Zotero / Mendeley / BibTeX integration is a future enhancement.
|
|
154
|
+
- **DOI auto-resolution.** Footnote text is plain — paste a DOI manually.
|
|
155
|
+
- **Per-page footnotes (Phase 3).** The editor uses end-of-doc placement;
|
|
156
|
+
per-page placement is a print-layout concern handled at book-export
|
|
157
|
+
time, not in the editor.
|
|
158
|
+
|
|
159
|
+
## When to use footnotes vs inline parentheticals
|
|
160
|
+
|
|
161
|
+
Use footnotes when:
|
|
162
|
+
- The citation count exceeds ~3 per ~500 words (inline parentheticals
|
|
163
|
+
start visibly disrupting the prose at that density)
|
|
164
|
+
- The audience expects an academic register (popular nonfiction in the
|
|
165
|
+
Sapolsky / Wrangham / Pinker lineage)
|
|
166
|
+
- The work targets book-class output (cumulative citation load at book
|
|
167
|
+
scale destroys readability under inline parentheticals)
|
|
168
|
+
|
|
169
|
+
Use inline parentheticals when:
|
|
170
|
+
- Citations are sparse (<1 per 500 words) and short
|
|
171
|
+
- The author prefers a journalistic register
|
|
172
|
+
- The work is short-form (tweet thread, blog post) where there's no
|
|
173
|
+
end-of-doc section to defer to
|
|
174
|
+
|
|
175
|
+
## Reference docs (for the editor maintainers, not agents)
|
|
176
|
+
|
|
177
|
+
- `docs/footnotes.md` (in the openwriter repo): full architecture
|
|
178
|
+
- `adr/footnote-system.md`: load-bearing invariants + decision log
|