writedock-mcp 0.4.4 → 0.4.7

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 (36) hide show
  1. package/README.md +21 -20
  2. package/extension/LICENSE-MULTIPOST.txt +201 -0
  3. package/extension/LICENSE.txt +674 -0
  4. package/extension/NOTICE.txt +13 -0
  5. package/extension/assets/editor-ClIT9WYa.js +76 -0
  6. package/extension/assets/editor-VBFqqvXW.css +1 -0
  7. package/extension/assets/icon-128.png +0 -0
  8. package/extension/assets/icon-16.png +0 -0
  9. package/extension/assets/icon-48.png +0 -0
  10. package/extension/assets/index.browser-Hs3ZYqOv.js +157 -0
  11. package/extension/assets/index.ts-BEVXnN62.js +42 -0
  12. package/extension/assets/logo.svg +5 -0
  13. package/extension/assets/offscreen-3BECPbQX.js +63 -0
  14. package/extension/assets/purify.es-1yEQDPgc.js +3 -0
  15. package/extension/assets/react-vendor-BrXlnJmF.js +40 -0
  16. package/extension/assets/task-utils-DwzGcJkm.js +1 -0
  17. package/extension/manifest.json +40 -0
  18. package/extension/service-worker-loader.js +1 -0
  19. package/extension/src/editor/index.html +16 -0
  20. package/extension/src/offscreen/index.html +6 -0
  21. package/extension/zhihu-publication-observer.js +1 -0
  22. package/extension//345/256/211/350/243/205/344/270/216/346/233/264/346/226/260.txt +19 -0
  23. package/index.cjs +290 -131
  24. package/package.json +3 -2
  25. package/source/package.json +1 -1
  26. package/source/src/__tests__/bridge.test.ts +22 -0
  27. package/source/src/__tests__/extension-update.test.ts +54 -0
  28. package/source/src/__tests__/setup.test.ts +50 -0
  29. package/source/src/bridge.ts +43 -61
  30. package/source/src/extension-id.ts +2 -0
  31. package/source/src/extension-update.ts +82 -0
  32. package/source/src/identity.ts +2 -2
  33. package/source/src/index.ts +3 -0
  34. package/source/src/release-info.ts +3 -0
  35. package/source/src/server.ts +2 -6
  36. package/source/src/setup.ts +88 -0
@@ -0,0 +1,88 @@
1
+ import { spawn } from 'node:child_process'
2
+ import { copyFile, mkdir, readFile, writeFile } from 'node:fs/promises'
3
+ import { homedir } from 'node:os'
4
+ import { dirname, join } from 'node:path'
5
+ import { bundledExtension, defaultExtensionDirectory, findInstalledExtension, installExtensionFiles } from './extension-update'
6
+
7
+ const COMMAND = 'npx'
8
+ const ARGS = ['-y', '--prefer-online', 'writedock-mcp@latest']
9
+
10
+ async function readIfPresent(path: string) {
11
+ try { return await readFile(path, 'utf8') }
12
+ catch (error) { if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined; throw error }
13
+ }
14
+
15
+ async function save(path: string, content: string, previous: string | undefined) {
16
+ await mkdir(dirname(path), { recursive: true })
17
+ if (previous !== undefined) await copyFile(path, `${path}.writedock-backup`)
18
+ await writeFile(path, content)
19
+ }
20
+
21
+ /** Keeps the user's other settings; an existing WriteDock entry stays, because it may hold a custom port or data directory. */
22
+ export async function configureCodex(path: string): Promise<'added' | 'present'> {
23
+ const previous = await readIfPresent(path)
24
+ if (previous !== undefined && /^\s*\[mcp_servers\.writedock\]/m.test(previous)) return 'present'
25
+ const entry = `[mcp_servers.writedock]\ncommand = "${COMMAND}"\nargs = ${JSON.stringify(ARGS)}\nstartup_timeout_sec = 120\n`
26
+ await save(path, previous ? `${previous.replace(/\s*$/, '')}\n\n${entry}` : entry, previous)
27
+ return 'added'
28
+ }
29
+
30
+ export async function configureJsonClient(path: string): Promise<'added' | 'present'> {
31
+ const previous = await readIfPresent(path)
32
+ const config = previous?.trim() ? JSON.parse(previous) as { mcpServers?: Record<string, unknown> } : {}
33
+ if (config.mcpServers?.writedock) return 'present'
34
+ config.mcpServers = { ...config.mcpServers, writedock: { command: COMMAND, args: ARGS } }
35
+ await save(path, `${JSON.stringify(config, null, 2)}\n`, previous)
36
+ return 'added'
37
+ }
38
+
39
+ const exists = async (path: string) => (await readIfPresent(path)) !== undefined
40
+
41
+ /** Best effort: shows the folder so the user can pick it, or drag it onto the extensions page. */
42
+ function revealFolder(path: string) {
43
+ const command = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'explorer' : 'xdg-open'
44
+ try { const child = spawn(command, [path], { detached: true, stdio: 'ignore' }); child.on('error', () => {}); child.unref() } catch { /* The path is printed as well. */ }
45
+ }
46
+
47
+ /** Only clients already on this computer are configured, so setup never creates settings for an app the user does not have. */
48
+ export async function runSetup(home = homedir(), log: (line: string) => void = console.log) {
49
+ const clients: { name: string; path: string; detect: string; configure: (path: string) => Promise<'added' | 'present'> }[] = [
50
+ { name: 'Codex', path: join(home, '.codex/config.toml'), detect: join(home, '.codex/config.toml'), configure: configureCodex },
51
+ { name: 'Claude Code', path: join(home, '.claude.json'), detect: join(home, '.claude.json'), configure: configureJsonClient },
52
+ { name: 'Cursor', path: join(home, '.cursor/mcp.json'), detect: join(home, '.cursor/mcp.json'), configure: configureJsonClient },
53
+ { name: 'Claude Desktop', path: join(home, 'Library/Application Support/Claude/claude_desktop_config.json'), detect: join(home, 'Library/Application Support/Claude/claude_desktop_config.json'), configure: configureJsonClient },
54
+ ]
55
+ let found = 0
56
+ for (const client of clients) {
57
+ if (!await exists(client.detect)) continue
58
+ found++
59
+ try {
60
+ const state = await client.configure(client.path)
61
+ log(state === 'added' ? `✓ ${client.name}:已添加 WriteDock(原配置备份为 .writedock-backup)` : `✓ ${client.name}:已有 WriteDock 配置,未改动`)
62
+ } catch (error) { log(`✗ ${client.name}:配置失败(${error instanceof Error ? error.message : String(error)}),原文件未改动`) }
63
+ }
64
+ if (!found) {
65
+ log('没有找到已知的 agent 客户端。请在你的客户端里添加这个 MCP 服务:')
66
+ log(JSON.stringify({ mcpServers: { writedock: { command: COMMAND, args: ARGS } } }, null, 2))
67
+ }
68
+ // Keep whichever folder the browser already loads, so a repeat setup does not ask for another manual load.
69
+ const bundle = bundledExtension()
70
+ const loaded = bundle ? await findInstalledExtension().catch(() => undefined) : undefined
71
+ let extensionFolder: string | undefined
72
+ if (bundle) {
73
+ try { extensionFolder = (await installExtensionFiles(bundle.directory, loaded || defaultExtensionDirectory(home))).directory }
74
+ catch (error) { log(`✗ 扩展:安装失败(${error instanceof Error ? error.message : String(error)})`) }
75
+ }
76
+ log('')
77
+ log('接下来:')
78
+ log('1. 重启你的 agent 客户端,让它加载 WriteDock。')
79
+ if (extensionFolder && !loaded) {
80
+ log('2. 在 Chrome 或 Edge 打开 chrome://extensions,打开右上角的“开发者模式”,点“加载已解压的扩展程序”,选择这个文件夹:')
81
+ log(` ${extensionFolder}`)
82
+ revealFolder(extensionFolder)
83
+ log('3. 打开 WriteDock 扩展,点“连接”。')
84
+ } else if (extensionFolder) {
85
+ log(`2. 扩展已更新。在 chrome://extensions 点一次 WriteDock 的刷新图标,然后点“连接”。`)
86
+ } else log('2. 打开浏览器的 WriteDock 扩展,点“连接”。')
87
+ return found
88
+ }