openwriter 0.6.0 → 0.6.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/dist/server/install-skill.js +119 -2
- package/package.json +1 -1
- package/skill/SKILL.md +12 -15
|
@@ -1,19 +1,136 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import os from 'os';
|
|
4
|
+
import { execSync } from 'child_process';
|
|
4
5
|
import { fileURLToPath } from 'url';
|
|
5
6
|
const __filename = fileURLToPath(import.meta.url);
|
|
6
7
|
const __dirname = path.dirname(__filename);
|
|
8
|
+
function log(msg) {
|
|
9
|
+
console.error(msg);
|
|
10
|
+
}
|
|
11
|
+
function isGloballyInstalled() {
|
|
12
|
+
try {
|
|
13
|
+
const result = execSync('openwriter --version', {
|
|
14
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
15
|
+
timeout: 10000,
|
|
16
|
+
});
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function installGlobally() {
|
|
24
|
+
log('\n② Installing openwriter globally...');
|
|
25
|
+
// Try without sudo first (works on Windows, nvm, Homebrew, volta, etc.)
|
|
26
|
+
try {
|
|
27
|
+
execSync('npm install -g openwriter', { stdio: 'inherit', timeout: 120000 });
|
|
28
|
+
log(' ✓ Installed globally');
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// Likely permission error on macOS/Linux system Node
|
|
33
|
+
}
|
|
34
|
+
// Try with sudo on non-Windows
|
|
35
|
+
if (process.platform !== 'win32') {
|
|
36
|
+
log(' Retrying with sudo...');
|
|
37
|
+
try {
|
|
38
|
+
execSync('sudo npm install -g openwriter', { stdio: 'inherit', timeout: 120000 });
|
|
39
|
+
log(' ✓ Installed globally (sudo)');
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// sudo failed too
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
log(' ✗ Could not install globally. Run manually:');
|
|
47
|
+
log(' npm install -g openwriter');
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
function isMcpConfigured() {
|
|
51
|
+
const claudeJson = path.join(os.homedir(), '.claude.json');
|
|
52
|
+
if (!fs.existsSync(claudeJson))
|
|
53
|
+
return false;
|
|
54
|
+
try {
|
|
55
|
+
const content = JSON.parse(fs.readFileSync(claudeJson, 'utf-8'));
|
|
56
|
+
return !!content?.mcpServers?.openwriter;
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function configureMcp() {
|
|
63
|
+
log('\n③ Configuring MCP server for Claude Code...');
|
|
64
|
+
// Try using claude CLI
|
|
65
|
+
try {
|
|
66
|
+
execSync('claude mcp add -s user openwriter -- openwriter --no-open', {
|
|
67
|
+
stdio: 'inherit',
|
|
68
|
+
timeout: 15000,
|
|
69
|
+
});
|
|
70
|
+
log(' ✓ MCP server configured');
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
// claude CLI not available or failed
|
|
75
|
+
}
|
|
76
|
+
// Fallback: edit ~/.claude.json directly
|
|
77
|
+
log(' claude CLI not found — writing config directly...');
|
|
78
|
+
const claudeJson = path.join(os.homedir(), '.claude.json');
|
|
79
|
+
try {
|
|
80
|
+
let config = {};
|
|
81
|
+
if (fs.existsSync(claudeJson)) {
|
|
82
|
+
config = JSON.parse(fs.readFileSync(claudeJson, 'utf-8'));
|
|
83
|
+
}
|
|
84
|
+
if (!config.mcpServers)
|
|
85
|
+
config.mcpServers = {};
|
|
86
|
+
// Add openwriter as first entry (Claude Code loads sequentially)
|
|
87
|
+
const existing = config.mcpServers;
|
|
88
|
+
config.mcpServers = {
|
|
89
|
+
openwriter: { command: 'openwriter', args: ['--no-open'] },
|
|
90
|
+
...existing,
|
|
91
|
+
};
|
|
92
|
+
fs.writeFileSync(claudeJson, JSON.stringify(config, null, 2), 'utf-8');
|
|
93
|
+
log(` ✓ MCP server added to ${claudeJson}`);
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
log(` ✗ Could not configure MCP server. Add manually:`);
|
|
98
|
+
log(' claude mcp add -s user openwriter -- openwriter --no-open');
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
7
102
|
export function installSkill() {
|
|
103
|
+
// Step 1: Copy SKILL.md
|
|
104
|
+
log('① Installing OpenWriter skill...');
|
|
8
105
|
const source = path.join(__dirname, '../../skill/SKILL.md');
|
|
9
106
|
const targetDir = path.join(os.homedir(), '.claude', 'skills', 'openwriter');
|
|
10
107
|
const target = path.join(targetDir, 'SKILL.md');
|
|
11
108
|
if (!fs.existsSync(source)) {
|
|
12
|
-
|
|
109
|
+
log(` Error: SKILL.md not found at ${source}`);
|
|
13
110
|
process.exit(1);
|
|
14
111
|
}
|
|
15
112
|
fs.mkdirSync(targetDir, { recursive: true });
|
|
16
113
|
fs.copyFileSync(source, target);
|
|
17
|
-
|
|
114
|
+
log(` ✓ Skill installed to ${target}`);
|
|
115
|
+
// Step 2: Global install (skip if already installed)
|
|
116
|
+
const alreadyInstalled = isGloballyInstalled();
|
|
117
|
+
if (alreadyInstalled) {
|
|
118
|
+
log('\n② openwriter already installed globally — skipping');
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
if (!installGlobally()) {
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Step 3: Configure MCP server (skip if already configured)
|
|
126
|
+
if (isMcpConfigured()) {
|
|
127
|
+
log('\n③ MCP server already configured — skipping');
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
configureMcp();
|
|
131
|
+
}
|
|
132
|
+
// Done
|
|
133
|
+
log('\n✓ OpenWriter is ready!');
|
|
134
|
+
log(' Restart Claude Code, then type /openwriter to start writing.\n');
|
|
18
135
|
process.exit(0);
|
|
19
136
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openwriter",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
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",
|
package/skill/SKILL.md
CHANGED
|
@@ -36,30 +36,31 @@ Check whether the `openwriter` MCP tools are available (e.g. `read_pad`, `write_
|
|
|
36
36
|
|
|
37
37
|
### MCP tools ARE available (ready to use)
|
|
38
38
|
|
|
39
|
-
The user already has OpenWriter configured
|
|
39
|
+
The user already has OpenWriter configured. You're good to go.
|
|
40
40
|
|
|
41
41
|
**First action:** Share the browser URL:
|
|
42
42
|
> OpenWriter is at **http://localhost:5050** — open it in your browser to see and review changes.
|
|
43
43
|
|
|
44
44
|
Skip to [Writing Strategy](#writing-strategy) below.
|
|
45
45
|
|
|
46
|
-
### MCP tools are NOT available (
|
|
46
|
+
### MCP tools are NOT available (needs setup)
|
|
47
47
|
|
|
48
|
-
The user
|
|
48
|
+
The user has this skill but hasn't set up the MCP server yet. One command does everything:
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
```bash
|
|
51
|
+
npx openwriter install-skill
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
This installs openwriter globally, configures the MCP server for Claude Code, and copies this skill — all in one step. After it finishes, the user just needs to restart their Claude Code session.
|
|
55
|
+
|
|
56
|
+
**Fallback (if the command above fails):** Do it manually:
|
|
51
57
|
|
|
52
58
|
```bash
|
|
53
|
-
# Install globally for instant startup (no npx resolution delay)
|
|
54
59
|
npm install -g openwriter
|
|
55
|
-
|
|
56
|
-
# Add the OpenWriter MCP server to Claude Code
|
|
57
60
|
claude mcp add -s user openwriter -- openwriter --no-open
|
|
58
61
|
```
|
|
59
62
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
**Step 2 (if the user can't run the command above):** Edit `~/.claude.json` directly. Add `openwriter` as the **first entry** in the `mcpServers` object — MCP servers load sequentially, so first in config = first to load:
|
|
63
|
+
If `claude mcp add` can't run (e.g. nested session error), edit `~/.claude.json` directly. Add `openwriter` as the **first entry** in `mcpServers`:
|
|
63
64
|
|
|
64
65
|
```json
|
|
65
66
|
{
|
|
@@ -72,14 +73,10 @@ Then restart the Claude Code session. The 57 MCP tools become available on next
|
|
|
72
73
|
}
|
|
73
74
|
```
|
|
74
75
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
After editing, tell the user:
|
|
76
|
+
After setup, tell the user:
|
|
78
77
|
1. Restart your Claude Code session (MCP servers load on startup)
|
|
79
78
|
2. Open http://localhost:5050 in your browser
|
|
80
79
|
|
|
81
|
-
**Note:** You cannot run `claude mcp add` from inside a session (nested session error). That's why we edit the JSON directly when configuring from within Claude Code. Also, `claude mcp add` appends to the end — always verify the entry is first after adding.
|
|
82
|
-
|
|
83
80
|
## Document Identity: Titles vs DocIds
|
|
84
81
|
|
|
85
82
|
Every document has an immutable **docId** (8-char hex, e.g. `a1b2c3d4`) in its YAML frontmatter. Titles are for human communication and agent reasoning. DocIds are for agent action.
|