slima-mcp 0.1.3 → 0.1.4

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/index.js CHANGED
@@ -148,6 +148,18 @@ var SlimaApiClient = class {
148
148
  async getBook(token) {
149
149
  return this.request("GET", `/api/v1/books/${token}`);
150
150
  }
151
+ /**
152
+ * 建立新書籍
153
+ */
154
+ async createBook(params) {
155
+ return this.request("POST", "/api/v1/books", {
156
+ book: {
157
+ title: params.title,
158
+ author_name: params.authorName,
159
+ description: params.description
160
+ }
161
+ });
162
+ }
151
163
  // === 版本控制相關 ===
152
164
  /**
153
165
  * 列出 Commits
@@ -325,6 +337,43 @@ var SlimaApiClient = class {
325
337
  // src/tools/books.ts
326
338
  import { z } from "zod";
327
339
  function registerBookTools(server, client) {
340
+ server.tool(
341
+ "create_book",
342
+ "Create a new book in your Slima library",
343
+ {
344
+ title: z.string().describe("Book title (required)"),
345
+ author_name: z.string().optional().describe("Author name (optional)"),
346
+ description: z.string().optional().describe("Book description (optional)")
347
+ },
348
+ async ({ title, author_name, description }) => {
349
+ try {
350
+ const book = await client.createBook({
351
+ title,
352
+ authorName: author_name,
353
+ description
354
+ });
355
+ return {
356
+ content: [
357
+ {
358
+ type: "text",
359
+ text: `\u2705 Book created successfully!
360
+
361
+ - **Title**: ${book.title}
362
+ - **Token**: ${book.token}
363
+ - **Author**: ${book.authorName || "N/A"}
364
+
365
+ You can now add files using create_file with book_token: ${book.token}`
366
+ }
367
+ ]
368
+ };
369
+ } catch (error) {
370
+ return {
371
+ content: [{ type: "text", text: formatErrorForMcp(error) }],
372
+ isError: true
373
+ };
374
+ }
375
+ }
376
+ );
328
377
  server.tool(
329
378
  "list_books",
330
379
  "List all books in your Slima library",
@@ -1282,7 +1331,7 @@ function createSlimaServer(config) {
1282
1331
  });
1283
1332
  const server = new McpServer({
1284
1333
  name: "slima",
1285
- version: "0.1.3"
1334
+ version: "0.1.4"
1286
1335
  });
1287
1336
  registerBookTools(server, client);
1288
1337
  registerContentTools(server, client);
@@ -1611,7 +1660,7 @@ async function runStatus() {
1611
1660
  }
1612
1661
 
1613
1662
  // src/index.ts
1614
- var VERSION = "0.1.3";
1663
+ var VERSION = "0.1.4";
1615
1664
  function showHelp() {
1616
1665
  console.log(`
1617
1666
  Slima MCP v${VERSION}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/server.ts","../src/utils/errors.ts","../src/utils/logger.ts","../src/api/client.ts","../src/tools/books.ts","../src/tools/content.ts","../src/tools/beta-reader.ts","../src/tools/files.ts","../src/utils/token-storage.ts","../src/cli/auth.ts"],"sourcesContent":["/**\n * Slima MCP Server - CLI Entry Point\n *\n * Usage:\n * slima-mcp - Start MCP server (requires SLIMA_API_TOKEN or prior auth)\n * slima-mcp auth - Authenticate with Slima (opens browser)\n * slima-mcp logout - Remove saved credentials\n * slima-mcp status - Show authentication status\n * slima-mcp --help - Show help\n */\n\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { createSlimaServer } from './server.js';\nimport { logger } from './utils/logger.js';\nimport { loadToken, getCredentialsFilePath } from './utils/token-storage.js';\nimport { runAuth, runLogout, runStatus } from './cli/auth.js';\n\ndeclare const __VERSION__: string;\nconst VERSION = __VERSION__;\n\nfunction showHelp(): void {\n console.log(`\nSlima MCP v${VERSION}\nMCP Server for Slima - AI Writing IDE for Novel Authors\n\nUSAGE:\n slima-mcp [command]\n\nCOMMANDS:\n (none) Start the MCP server\n auth Authenticate with Slima (opens browser)\n logout Remove saved credentials\n status Show authentication status\n --help Show this help message\n --version Show version\n\nAUTHENTICATION:\n 1. Run: slima-mcp auth\n 2. Complete authentication in browser\n 3. Token is automatically saved\n\n Or set SLIMA_API_TOKEN environment variable.\n\nEXAMPLES:\n slima-mcp auth # Authenticate with browser\n slima-mcp status # Check auth status\n SLIMA_API_TOKEN=xxx slima-mcp # Use env var\n\nCONFIGURATION (for AI tools):\n Claude Desktop, Cursor, etc.:\n {\n \"mcpServers\": {\n \"slima\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"slima-mcp\"]\n }\n }\n }\n\nMORE INFO:\n https://github.com/slima-ai/slima-mcp\n`);\n}\n\nfunction showVersion(): void {\n console.log(`slima-mcp v${VERSION}`);\n}\n\nasync function startServer(): Promise<void> {\n // 優先使用環境變數,否則使用儲存的 token\n let apiToken = process.env.SLIMA_API_TOKEN;\n let baseUrl = process.env.SLIMA_API_URL;\n\n if (!apiToken) {\n const credentials = await loadToken();\n if (credentials) {\n apiToken = credentials.apiToken;\n baseUrl = baseUrl || credentials.baseUrl;\n }\n }\n\n if (!apiToken) {\n logger.error('Not authenticated and SLIMA_API_TOKEN not set');\n logger.error('');\n logger.error('To authenticate, run:');\n logger.error(' slima-mcp auth');\n logger.error('');\n logger.error('Or set environment variable:');\n logger.error(' SLIMA_API_TOKEN=your_token slima-mcp');\n logger.error('');\n logger.error('Get your API token from: https://app.slima.ai/settings/api-tokens');\n process.exit(1);\n }\n\n try {\n const server = createSlimaServer({\n apiToken,\n baseUrl,\n });\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n logger.info('Slima MCP Server running on stdio');\n\n // 優雅關閉\n process.on('SIGINT', async () => {\n logger.info('Shutting down...');\n await server.close();\n process.exit(0);\n });\n\n process.on('SIGTERM', async () => {\n logger.info('Shutting down...');\n await server.close();\n process.exit(0);\n });\n } catch (error) {\n logger.error('Failed to start server', error);\n process.exit(1);\n }\n}\n\nasync function main(): Promise<void> {\n const args = process.argv.slice(2);\n const command = args[0];\n\n switch (command) {\n case 'auth':\n await runAuth();\n break;\n\n case 'logout':\n await runLogout();\n break;\n\n case 'status':\n await runStatus();\n break;\n\n case '--help':\n case '-h':\n case 'help':\n showHelp();\n break;\n\n case '--version':\n case '-v':\n showVersion();\n break;\n\n case undefined:\n // 預設:啟動 MCP server\n await startServer();\n break;\n\n default:\n console.error(`Unknown command: ${command}`);\n console.error('Run `slima-mcp --help` for usage.');\n process.exit(1);\n }\n}\n\nmain();\n","/**\n * Slima MCP Server\n */\n\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { SlimaApiClient } from './api/client.js';\nimport { registerBookTools } from './tools/books.js';\nimport { registerContentTools } from './tools/content.js';\nimport { registerBetaReaderTools } from './tools/beta-reader.js';\nimport { registerFileTools } from './tools/files.js';\nimport { logger } from './utils/logger.js';\n\ndeclare const __VERSION__: string;\n\nexport interface ServerConfig {\n apiToken: string;\n baseUrl?: string;\n}\n\n/**\n * 建立 Slima MCP Server\n */\nexport function createSlimaServer(config: ServerConfig): McpServer {\n const client = new SlimaApiClient({\n token: config.apiToken,\n baseUrl: config.baseUrl || 'https://api.slima.ai',\n });\n\n const server = new McpServer({\n name: 'slima',\n version: __VERSION__,\n });\n\n // 註冊工具\n registerBookTools(server, client);\n registerContentTools(server, client);\n registerBetaReaderTools(server, client);\n registerFileTools(server, client);\n\n logger.info('Slima MCP Server initialized');\n logger.info(`API endpoint: ${config.baseUrl || 'https://api.slima.ai'}`);\n\n return server;\n}\n","/**\n * 錯誤處理工具\n */\n\nexport class SlimaApiError extends Error {\n constructor(\n public status: number,\n public code?: string,\n message?: string\n ) {\n super(message || `API Error: ${status}`);\n this.name = 'SlimaApiError';\n }\n}\n\nexport class AuthenticationError extends SlimaApiError {\n constructor(message = 'Invalid or expired API token') {\n super(401, 'UNAUTHORIZED', message);\n this.name = 'AuthenticationError';\n }\n}\n\nexport class NotFoundError extends SlimaApiError {\n constructor(resource = 'Resource') {\n super(404, 'NOT_FOUND', `${resource} not found`);\n this.name = 'NotFoundError';\n }\n}\n\nexport class InsufficientCreditsError extends SlimaApiError {\n constructor() {\n super(402, 'INSUFFICIENT_CREDITS', 'Insufficient credits');\n this.name = 'InsufficientCreditsError';\n }\n}\n\n/**\n * 格式化錯誤訊息供 MCP 回傳\n */\nexport function formatErrorForMcp(error: unknown): string {\n if (error instanceof SlimaApiError) {\n switch (error.code) {\n case 'NOT_FOUND':\n return 'Resource not found. Please check the token.';\n case 'UNAUTHORIZED':\n return 'Invalid API token. Please check your configuration.';\n case 'INSUFFICIENT_CREDITS':\n return 'Insufficient credits. Please top up your account.';\n case 'TOKEN_EXPIRED':\n return 'API token has expired. Please generate a new one.';\n case 'TOKEN_REVOKED':\n return 'API token has been revoked. Please generate a new one.';\n default:\n return error.message;\n }\n }\n\n if (error instanceof Error) {\n return error.message;\n }\n\n return 'An unexpected error occurred.';\n}\n","/**\n * Logger 工具\n *\n * 重要:MCP STDIO 模式下,stdout 是協議通道,\n * 所有日誌必須輸出到 stderr\n */\n\nconst isDebug = process.env.DEBUG === 'true' || process.env.DEBUG === '1';\n\nexport const logger = {\n info: (message: string, ...args: unknown[]) => {\n console.error(`[INFO] ${message}`, ...args);\n },\n\n warn: (message: string, ...args: unknown[]) => {\n console.error(`[WARN] ${message}`, ...args);\n },\n\n error: (message: string, error?: unknown) => {\n if (error instanceof Error) {\n console.error(`[ERROR] ${message}:`, error.message);\n if (isDebug && error.stack) {\n console.error(error.stack);\n }\n } else if (error !== undefined) {\n console.error(`[ERROR] ${message}:`, error);\n } else {\n console.error(`[ERROR] ${message}`);\n }\n },\n\n debug: (message: string, ...args: unknown[]) => {\n if (isDebug) {\n console.error(`[DEBUG] ${message}`, ...args);\n }\n },\n};\n","/**\n * Slima API Client\n */\n\nimport {\n type Book,\n type Commit,\n type Branch,\n type Blob,\n type Persona,\n type ReaderTest,\n type ReaderTestProgress,\n type CreateReaderTestParams,\n type ApiResponse,\n type ApiError,\n type CommitsListResponse,\n type BlobsDownloadResponse,\n type McpFileReadResponse,\n type McpFileCreateResponse,\n type McpFileUpdateResponse,\n type McpFileDeleteResponse,\n type McpFileAppendResponse,\n type McpSearchResponse,\n} from './types.js';\nimport {\n SlimaApiError,\n AuthenticationError,\n NotFoundError,\n InsufficientCreditsError,\n} from '../utils/errors.js';\nimport { logger } from '../utils/logger.js';\n\nexport interface SlimaConfig {\n baseUrl: string;\n token: string;\n}\n\nexport class SlimaApiClient {\n private readonly baseUrl: string;\n private readonly token: string;\n\n constructor(config: SlimaConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, ''); // 移除尾部斜線\n this.token = config.token;\n }\n\n /**\n * 發送 API 請求\n */\n private async request<T>(\n method: string,\n path: string,\n body?: unknown\n ): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n logger.debug(`${method} ${path}`);\n\n const response = await fetch(url, {\n method,\n headers: {\n Authorization: `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n 'User-Agent': 'slima-mcp-server/0.1.0',\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n await this.handleErrorResponse(response);\n }\n\n const json = (await response.json()) as ApiResponse<T>;\n return json.data;\n }\n\n /**\n * 處理錯誤回應\n */\n private async handleErrorResponse(response: Response): Promise<never> {\n let errorData: ApiError | undefined;\n\n try {\n errorData = (await response.json()) as ApiError;\n } catch {\n // 無法解析 JSON\n }\n\n const code = errorData?.error?.code;\n const message = errorData?.error?.message;\n\n switch (response.status) {\n case 401:\n throw new AuthenticationError(message);\n case 404:\n throw new NotFoundError(message);\n case 402:\n throw new InsufficientCreditsError();\n default:\n throw new SlimaApiError(response.status, code, message);\n }\n }\n\n // === 書籍相關 ===\n\n /**\n * 列出所有書籍\n */\n async listBooks(): Promise<Book[]> {\n return this.request<Book[]>('GET', '/api/v1/books');\n }\n\n /**\n * 取得書籍詳情\n */\n async getBook(token: string): Promise<Book> {\n return this.request<Book>('GET', `/api/v1/books/${token}`);\n }\n\n // === 版本控制相關 ===\n\n /**\n * 列出 Commits\n * 注意:API 回傳 { commits: [...] },需要解構\n */\n async listCommits(bookToken: string, limit = 10): Promise<Commit[]> {\n const response = await this.request<CommitsListResponse>(\n 'GET',\n `/api/v1/books/${bookToken}/commits?limit=${limit}`\n );\n return response.commits;\n }\n\n /**\n * 取得 Commit 詳情\n */\n async getCommit(bookToken: string, commitToken: string): Promise<Commit> {\n return this.request<Commit>(\n 'GET',\n `/api/v1/books/${bookToken}/commits/${commitToken}`\n );\n }\n\n /**\n * 列出分支\n */\n async listBranches(bookToken: string): Promise<Branch[]> {\n return this.request<Branch[]>('GET', `/api/v1/books/${bookToken}/branches`);\n }\n\n /**\n * 下載 Blobs\n * 注意:API 回傳 { blobs: [...], notFound: [...], truncated: ... }\n */\n async downloadBlobs(bookToken: string, hashes: string[]): Promise<Blob[]> {\n const response = await this.request<BlobsDownloadResponse>(\n 'POST',\n `/api/v1/books/${bookToken}/blobs/download`,\n { hashes }\n );\n return response.blobs;\n }\n\n // === Persona 相關 ===\n\n /**\n * 列出所有 Personas\n */\n async listPersonas(genre?: string): Promise<Persona[]> {\n const params = genre ? `?genre=${encodeURIComponent(genre)}` : '';\n return this.request<Persona[]>('GET', `/api/v1/personas${params}`);\n }\n\n /**\n * 取得 Persona 詳情\n */\n async getPersona(token: string): Promise<Persona> {\n return this.request<Persona>('GET', `/api/v1/personas/${token}`);\n }\n\n // === Reader Test 相關 ===\n\n /**\n * 建立 Reader Test\n */\n async createReaderTest(\n bookToken: string,\n params: CreateReaderTestParams\n ): Promise<ReaderTest> {\n return this.request<ReaderTest>(\n 'POST',\n `/api/v1/books/${bookToken}/reader_tests`,\n {\n reader_test: {\n report_type: params.reportType || 'chapter',\n persona_tokens: params.personaTokens,\n commit_token: params.commitToken,\n model: params.model,\n scope_config: params.scopeConfig,\n },\n content: params.content,\n }\n );\n }\n\n /**\n * 取得 Reader Test 進度\n */\n async getReaderTestProgress(\n bookToken: string,\n testToken: string\n ): Promise<ReaderTestProgress> {\n return this.request<ReaderTestProgress>(\n 'GET',\n `/api/v1/books/${bookToken}/reader_tests/${testToken}/progress`\n );\n }\n\n /**\n * 取得 Reader Test 結果\n */\n async getReaderTest(bookToken: string, testToken: string): Promise<ReaderTest> {\n return this.request<ReaderTest>(\n 'GET',\n `/api/v1/books/${bookToken}/reader_tests/${testToken}`\n );\n }\n\n // === MCP File Operations ===\n\n /**\n * 讀取檔案內容\n */\n async readFile(bookToken: string, path: string): Promise<McpFileReadResponse> {\n return this.request<McpFileReadResponse>(\n 'POST',\n `/api/v1/books/${bookToken}/mcp/files/read`,\n { path }\n );\n }\n\n /**\n * 建立新檔案\n */\n async createFile(\n bookToken: string,\n params: { path: string; content?: string; parentPath?: string; commitMessage?: string }\n ): Promise<McpFileCreateResponse> {\n return this.request<McpFileCreateResponse>(\n 'POST',\n `/api/v1/books/${bookToken}/mcp/files/create`,\n {\n path: params.path,\n content: params.content || '',\n parent_path: params.parentPath,\n commit_message: params.commitMessage,\n }\n );\n }\n\n /**\n * 更新(覆寫)檔案內容\n */\n async updateFile(\n bookToken: string,\n params: { path: string; content: string; commitMessage?: string }\n ): Promise<McpFileUpdateResponse> {\n return this.request<McpFileUpdateResponse>(\n 'POST',\n `/api/v1/books/${bookToken}/mcp/files/update`,\n {\n path: params.path,\n content: params.content,\n commit_message: params.commitMessage,\n }\n );\n }\n\n /**\n * 刪除檔案\n */\n async deleteFile(\n bookToken: string,\n params: { path: string; commitMessage?: string }\n ): Promise<McpFileDeleteResponse> {\n return this.request<McpFileDeleteResponse>(\n 'POST',\n `/api/v1/books/${bookToken}/mcp/files/delete`,\n {\n path: params.path,\n commit_message: params.commitMessage,\n }\n );\n }\n\n /**\n * 附加內容到檔案\n */\n async appendToFile(\n bookToken: string,\n params: { path: string; content: string; commitMessage?: string }\n ): Promise<McpFileAppendResponse> {\n return this.request<McpFileAppendResponse>(\n 'POST',\n `/api/v1/books/${bookToken}/mcp/files/append`,\n {\n path: params.path,\n content: params.content,\n commit_message: params.commitMessage,\n }\n );\n }\n\n /**\n * 搜尋檔案內容\n */\n async searchFiles(\n bookToken: string,\n params: { query: string; fileTypes?: string[]; limit?: number }\n ): Promise<McpSearchResponse> {\n return this.request<McpSearchResponse>(\n 'POST',\n `/api/v1/books/${bookToken}/mcp/files/search`,\n {\n query: params.query,\n file_types: params.fileTypes,\n limit: params.limit,\n }\n );\n }\n}\n","/**\n * 書籍相關 Tools\n */\n\nimport { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { SlimaApiClient } from '../api/client.js';\nimport { formatErrorForMcp } from '../utils/errors.js';\nimport type { FileSnapshot } from '../api/types.js';\n\n/**\n * 註冊書籍相關工具\n */\nexport function registerBookTools(\n server: McpServer,\n client: SlimaApiClient\n): void {\n // === list_books ===\n server.tool(\n 'list_books',\n 'List all books in your Slima library',\n {},\n async () => {\n try {\n const books = await client.listBooks();\n\n if (books.length === 0) {\n return {\n content: [\n {\n type: 'text',\n text: 'No books found in your library.',\n },\n ],\n };\n }\n\n const formatted = books\n .map((book) => {\n const words = book.totalWordCount?.toLocaleString() || '0';\n return `- **${book.title}** (${book.token})\\n Author: ${book.authorName || 'N/A'} | Words: ${words}`;\n })\n .join('\\n\\n');\n\n return {\n content: [\n {\n type: 'text',\n text: `Found ${books.length} book(s):\\n\\n${formatted}`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: formatErrorForMcp(error) }],\n isError: true,\n };\n }\n }\n );\n\n // === get_book ===\n server.tool(\n 'get_book',\n 'Get details of a specific book',\n {\n book_token: z.string().describe('Book token (e.g., bk_abc123)'),\n },\n async ({ book_token }) => {\n try {\n const book = await client.getBook(book_token);\n\n const text = `# ${book.title}\n\n- **Token**: ${book.token}\n- **Author**: ${book.authorName || 'N/A'}\n- **Description**: ${book.description || 'N/A'}\n- **Language**: ${book.language || 'N/A'}\n- **Total Words**: ${book.totalWordCount?.toLocaleString() || '0'}\n- **Manuscript Words**: ${book.manuscriptWordCount?.toLocaleString() || '0'}\n- **Created**: ${book.createdAt}\n- **Updated**: ${book.updatedAt}`;\n\n return {\n content: [{ type: 'text', text }],\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: formatErrorForMcp(error) }],\n isError: true,\n };\n }\n }\n );\n\n // === get_book_structure ===\n server.tool(\n 'get_book_structure',\n 'Get the file/folder structure of a book',\n {\n book_token: z.string().describe('Book token'),\n },\n async ({ book_token }) => {\n try {\n const commits = await client.listCommits(book_token, 1);\n\n if (commits.length === 0) {\n return {\n content: [\n {\n type: 'text',\n text: 'No commits found. The book may be empty.',\n },\n ],\n };\n }\n\n const snapshot = commits[0].filesSnapshot;\n const tree = formatFileTree(snapshot);\n\n return {\n content: [\n {\n type: 'text',\n text: `File structure for book ${book_token}:\\n\\n${tree}`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: formatErrorForMcp(error) }],\n isError: true,\n };\n }\n }\n );\n\n // === get_writing_stats ===\n server.tool(\n 'get_writing_stats',\n 'Get writing statistics for a book',\n {\n book_token: z.string().describe('Book token'),\n },\n async ({ book_token }) => {\n try {\n const [book, commits] = await Promise.all([\n client.getBook(book_token),\n client.listCommits(book_token, 10),\n ]);\n\n // 計算最近的寫作進度\n let wordChange = 0;\n if (commits.length > 1) {\n const latest = commits[0].totalWordCount || 0;\n const oldest = commits[commits.length - 1].totalWordCount || 0;\n wordChange = latest - oldest;\n }\n\n const sign = wordChange >= 0 ? '+' : '';\n const progressText =\n commits.length > 1\n ? `${sign}${wordChange.toLocaleString()} words (last ${commits.length} commits)`\n : 'N/A (not enough history)';\n\n const text = `# Writing Stats: ${book.title}\n\n- **Total Words**: ${book.totalWordCount?.toLocaleString() || '0'}\n- **Manuscript Words**: ${book.manuscriptWordCount?.toLocaleString() || '0'}\n- **Recent Progress**: ${progressText}\n- **Commits Analyzed**: ${commits.length}\n- **Language**: ${book.language || 'N/A'}`;\n\n return {\n content: [{ type: 'text', text }],\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: formatErrorForMcp(error) }],\n isError: true,\n };\n }\n }\n );\n}\n\n/**\n * 格式化檔案樹\n */\nfunction formatFileTree(files: FileSnapshot[], indent = 0): string {\n return files\n .sort((a, b) => a.position - b.position)\n .map((f) => {\n const prefix = ' '.repeat(indent);\n const icon = f.kind === 'folder' ? '📁' : '📄';\n const words = f.kind === 'file' && f.wordCount ? ` (${f.wordCount} words)` : '';\n const manuscript = f.isManuscript ? ' [M]' : '';\n let line = `${prefix}${icon} ${f.name}${words}${manuscript}`;\n\n if (f.children && f.children.length > 0) {\n line += '\\n' + formatFileTree(f.children, indent + 1);\n }\n\n return line;\n })\n .join('\\n');\n}\n","/**\n * 內容存取 Tools\n */\n\nimport { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { SlimaApiClient } from '../api/client.js';\nimport { formatErrorForMcp } from '../utils/errors.js';\nimport type { FileSnapshot } from '../api/types.js';\n\n/**\n * 註冊內容存取工具\n */\nexport function registerContentTools(\n server: McpServer,\n client: SlimaApiClient\n): void {\n // === get_chapter ===\n server.tool(\n 'get_chapter',\n 'Read the content of a chapter or file from a book',\n {\n book_token: z.string().describe('Book token (e.g., bk_abc123)'),\n file_path: z.string().describe('File path (e.g., /chapters/01.md or chapter-01)'),\n },\n async ({ book_token, file_path }) => {\n try {\n // 1. 取得最新 commit\n const commits = await client.listCommits(book_token, 1);\n\n if (commits.length === 0) {\n return {\n content: [\n {\n type: 'text',\n text: 'No commits found. The book may be empty.',\n },\n ],\n };\n }\n\n // 2. 在 snapshot 中找到檔案\n const file = findFileInSnapshot(commits[0].filesSnapshot, file_path);\n\n if (!file) {\n // 列出可用的檔案\n const availableFiles = listAllFiles(commits[0].filesSnapshot);\n const fileList = availableFiles.slice(0, 10).join('\\n- ');\n const moreText =\n availableFiles.length > 10\n ? `\\n... and ${availableFiles.length - 10} more files`\n : '';\n\n return {\n content: [\n {\n type: 'text',\n text: `File not found: ${file_path}\\n\\nAvailable files:\\n- ${fileList}${moreText}\\n\\nTip: Use get_book_structure to see the full file tree.`,\n },\n ],\n isError: true,\n };\n }\n\n if (file.kind === 'folder') {\n return {\n content: [\n {\n type: 'text',\n text: `\"${file_path}\" is a folder, not a file. Please specify a file path.`,\n },\n ],\n isError: true,\n };\n }\n\n if (!file.blobHash) {\n return {\n content: [\n {\n type: 'text',\n text: `File \"${file_path}\" has no content (empty file).`,\n },\n ],\n };\n }\n\n // 3. 下載 blob 內容\n const blobs = await client.downloadBlobs(book_token, [file.blobHash]);\n\n if (blobs.length === 0) {\n return {\n content: [\n {\n type: 'text',\n text: 'Could not retrieve file content. The blob may be missing.',\n },\n ],\n isError: true,\n };\n }\n\n const content = blobs[0].content;\n const wordInfo = file.wordCount ? ` (${file.wordCount} words)` : '';\n\n return {\n content: [\n {\n type: 'text',\n text: `# ${file.name}${wordInfo}\\n\\n${content}`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: formatErrorForMcp(error) }],\n isError: true,\n };\n }\n }\n );\n}\n\n/**\n * 在 snapshot 中尋找檔案\n * 支援多種路徑格式:\n * - 完整路徑:/chapters/01.md\n * - 相對路徑:chapters/01.md\n * - 檔名:01.md\n * - Token:chapter-01\n */\nfunction findFileInSnapshot(\n files: FileSnapshot[],\n path: string\n): FileSnapshot | null {\n // 正規化路徑\n const normalizedPath = path.replace(/^\\//, '').toLowerCase();\n const pathParts = normalizedPath.split('/');\n\n // 遞迴搜尋\n function search(\n items: FileSnapshot[],\n remainingParts: string[]\n ): FileSnapshot | null {\n for (const item of items) {\n const itemNameLower = item.name.toLowerCase();\n const itemTokenLower = item.token.toLowerCase();\n\n // 完整路徑匹配\n if (remainingParts.length === 1) {\n const target = remainingParts[0];\n if (\n itemNameLower === target ||\n itemTokenLower === target ||\n itemNameLower.replace(/\\.[^.]+$/, '') === target.replace(/\\.[^.]+$/, '')\n ) {\n return item;\n }\n }\n\n // 資料夾匹配,繼續往下搜尋\n if (item.kind === 'folder' && item.children) {\n if (\n itemNameLower === remainingParts[0] ||\n itemTokenLower === remainingParts[0]\n ) {\n const result = search(item.children, remainingParts.slice(1));\n if (result) return result;\n }\n\n // 也嘗試在子資料夾中直接搜尋\n const result = search(item.children, remainingParts);\n if (result) return result;\n }\n }\n\n return null;\n }\n\n // 先嘗試完整路徑\n let result = search(files, pathParts);\n if (result) return result;\n\n // 再嘗試只用檔名搜尋\n result = searchByName(files, pathParts[pathParts.length - 1]);\n return result;\n}\n\n/**\n * 只用檔名搜尋\n */\nfunction searchByName(\n files: FileSnapshot[],\n name: string\n): FileSnapshot | null {\n const nameLower = name.toLowerCase();\n\n for (const item of files) {\n const itemNameLower = item.name.toLowerCase();\n const itemTokenLower = item.token.toLowerCase();\n\n if (\n itemNameLower === nameLower ||\n itemTokenLower === nameLower ||\n itemNameLower.replace(/\\.[^.]+$/, '') === nameLower.replace(/\\.[^.]+$/, '')\n ) {\n return item;\n }\n\n if (item.kind === 'folder' && item.children) {\n const result = searchByName(item.children, name);\n if (result) return result;\n }\n }\n\n return null;\n}\n\n/**\n * 列出所有檔案路徑\n */\nfunction listAllFiles(files: FileSnapshot[], prefix = ''): string[] {\n const result: string[] = [];\n\n for (const item of files) {\n const path = prefix ? `${prefix}/${item.name}` : item.name;\n\n if (item.kind === 'file') {\n result.push(path);\n } else if (item.children) {\n result.push(...listAllFiles(item.children, path));\n }\n }\n\n return result;\n}\n","/**\n * Beta Reader Tools\n */\n\nimport { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { SlimaApiClient } from '../api/client.js';\nimport { formatErrorForMcp } from '../utils/errors.js';\nimport type { FileSnapshot, ReaderTest, IndividualFeedback, AggregatedMetrics } from '../api/types.js';\nimport { logger } from '../utils/logger.js';\n\n/**\n * 註冊 Beta Reader 工具\n */\nexport function registerBetaReaderTools(\n server: McpServer,\n client: SlimaApiClient\n): void {\n // === list_personas ===\n server.tool(\n 'list_personas',\n 'List available virtual reader personas for beta reading feedback',\n {\n genre: z\n .string()\n .optional()\n .describe('Filter by genre (e.g., fantasy, romance, scifi)'),\n },\n async ({ genre }) => {\n try {\n const personas = await client.listPersonas(genre);\n\n if (personas.length === 0) {\n const genreText = genre ? ` for genre \"${genre}\"` : '';\n return {\n content: [\n {\n type: 'text',\n text: `No personas found${genreText}.`,\n },\n ],\n };\n }\n\n const formatted = personas\n .map((p) => {\n const name = p.displayLabels?.zh || p.displayLabels?.en || p.slug;\n const tags = p.genreTags?.join(', ') || 'General';\n const demo = p.demographics || {};\n const gender = demo.gender || 'N/A';\n const age = demo.ageRange || 'N/A';\n\n return `- **${name}** (\\`${p.token}\\`)\n Gender: ${gender} | Age: ${age}\n Genres: ${tags}`;\n })\n .join('\\n\\n');\n\n return {\n content: [\n {\n type: 'text',\n text: `Available Personas (${personas.length}):\\n\\n${formatted}\\n\\n**Tip**: Use the persona token with \\`analyze_chapter\\` to get feedback from a specific reader.`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: formatErrorForMcp(error) }],\n isError: true,\n };\n }\n }\n );\n\n // === analyze_chapter ===\n server.tool(\n 'analyze_chapter',\n 'Get AI Beta Reader feedback on a chapter from a specific reader persona. This may take a moment to complete.',\n {\n book_token: z.string().describe('Book token (e.g., bk_abc123)'),\n file_path: z.string().describe('Chapter file path (e.g., /chapters/01.md)'),\n persona_token: z\n .string()\n .describe('Persona token (e.g., psn_xxx). Use list_personas to find available personas.'),\n },\n async ({ book_token, file_path, persona_token }) => {\n try {\n // 1. 取得最新 commit 和章節內容\n const commits = await client.listCommits(book_token, 1);\n\n if (commits.length === 0) {\n return {\n content: [\n {\n type: 'text',\n text: 'No commits found. The book may be empty.',\n },\n ],\n isError: true,\n };\n }\n\n // 2. 找到檔案\n const file = findFileInSnapshot(commits[0].filesSnapshot, file_path);\n\n if (!file) {\n return {\n content: [\n {\n type: 'text',\n text: `File not found: ${file_path}. Use get_book_structure to see available files.`,\n },\n ],\n isError: true,\n };\n }\n\n if (!file.blobHash) {\n return {\n content: [\n {\n type: 'text',\n text: `File \"${file_path}\" has no content (empty file).`,\n },\n ],\n isError: true,\n };\n }\n\n // 3. 下載內容\n const blobs = await client.downloadBlobs(book_token, [file.blobHash]);\n\n if (blobs.length === 0) {\n return {\n content: [\n {\n type: 'text',\n text: 'Could not retrieve file content.',\n },\n ],\n isError: true,\n };\n }\n\n const content = blobs[0].content;\n\n // 4. 建立 Reader Test\n logger.info(`Creating reader test for ${file_path} with persona ${persona_token}`);\n\n const test = await client.createReaderTest(book_token, {\n reportType: 'chapter',\n personaTokens: [persona_token],\n commitToken: commits[0].token,\n scopeConfig: { chapters: [file_path] },\n content: content,\n });\n\n // 5. 輪詢等待完成(最多 90 秒)\n const result = await pollForCompletion(\n () => client.getReaderTestProgress(book_token, test.token),\n 90000\n );\n\n if (result.status === 'failed') {\n return {\n content: [\n {\n type: 'text',\n text: 'Analysis failed. Please try again later.',\n },\n ],\n isError: true,\n };\n }\n\n if (result.status !== 'completed') {\n return {\n content: [\n {\n type: 'text',\n text: `Analysis is still in progress. You can check the status later.\\n\\nTest ID: ${test.token}`,\n },\n ],\n };\n }\n\n // 6. 取得完整結果\n const fullResult = await client.getReaderTest(book_token, test.token);\n\n // 7. 格式化反饋\n const feedback = formatBetaReaderFeedback(fullResult, file.name);\n\n return {\n content: [{ type: 'text', text: feedback }],\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: formatErrorForMcp(error) }],\n isError: true,\n };\n }\n }\n );\n}\n\n/**\n * 輪詢等待完成\n */\nasync function pollForCompletion(\n checkFn: () => Promise<{ status: string; progress?: number }>,\n timeoutMs: number\n): Promise<{ status: string }> {\n const startTime = Date.now();\n const pollInterval = 3000; // 3 秒\n\n while (Date.now() - startTime < timeoutMs) {\n const result = await checkFn();\n logger.debug(`Poll status: ${result.status}, progress: ${result.progress || 'N/A'}`);\n\n if (result.status === 'completed' || result.status === 'failed') {\n return result;\n }\n\n await sleep(pollInterval);\n }\n\n return { status: 'timeout' };\n}\n\n/**\n * 睡眠\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * 格式化 Beta Reader 反饋 (English headers for better AI processing)\n */\nfunction formatBetaReaderFeedback(test: ReaderTest, fileName: string): string {\n const feedbacks = test.individualFeedbacks || [];\n const metrics = test.aggregatedMetrics;\n\n if (feedbacks.length === 0 && !metrics) {\n return 'No feedback available.';\n }\n\n let output = `# Beta Reader Feedback: ${fileName}\\n\\n`;\n\n // Aggregated metrics summary\n if (metrics) {\n output += formatAggregatedMetrics(metrics);\n }\n\n // Individual persona feedback\n if (feedbacks.length > 0) {\n output += `\\n---\\n\\n## Individual Reader Feedback\\n\\n`;\n output += feedbacks.map(formatIndividualFeedback).join('\\n---\\n\\n');\n }\n\n return output;\n}\n\n/**\n * 格式化聚合指標 (English headers for better AI processing)\n */\nfunction formatAggregatedMetrics(metrics: AggregatedMetrics): string {\n let output = `## Summary Metrics\\n\\n`;\n\n // Overall\n if (metrics.overall) {\n const o = metrics.overall;\n output += `### Overall Scores\\n`;\n if (o.avgContinueReading) output += `- Continue Reading Intent: ${o.avgContinueReading.toFixed(1)}/10\\n`;\n if (o.avgRecommendation) output += `- Recommendation Score: ${o.avgRecommendation.toFixed(1)}/10\\n`;\n if (o.avgWantMore) output += `- Want More: ${o.avgWantMore.toFixed(1)}/10\\n`;\n if (o.dnfRisk) output += `- DNF Risk: ${o.dnfRisk}\\n`;\n output += '\\n';\n }\n\n // Kindle Rating\n if (metrics.kindleRating) {\n output += `### Predicted Kindle Rating\\n`;\n output += `- Average Score: ⭐ ${metrics.kindleRating.avgScore.toFixed(1)}/5\\n`;\n if (metrics.kindleRating.individualScores) {\n const scores = metrics.kindleRating.individualScores\n .map(s => `${s.personaName || 'Reader'}: ${s.score}/5 (${s.confidence})`)\n .join(', ');\n output += `- Individual Scores: ${scores}\\n`;\n }\n output += '\\n';\n }\n\n // Characters\n if (metrics.characters) {\n const c = metrics.characters;\n output += `### Character Evaluation\\n`;\n if (c.avgProtagonistLikability) output += `- Protagonist Likability: ${c.avgProtagonistLikability.toFixed(1)}/10\\n`;\n if (c.avgMotivationClarity) output += `- Motivation Clarity: ${c.avgMotivationClarity.toFixed(1)}/10\\n`;\n if (c.avgDialogueNaturalness) output += `- Dialogue Naturalness: ${c.avgDialogueNaturalness.toFixed(1)}/10\\n`;\n output += '\\n';\n }\n\n // Pacing\n if (metrics.pacing) {\n const p = metrics.pacing;\n output += `### Pacing Evaluation\\n`;\n if (p.avgOverall) output += `- Overall Pacing: ${p.avgOverall.toFixed(1)}/10\\n`;\n if (p.consensus) output += `- Consensus: ${p.consensus}\\n`;\n if (p.commonDnfTriggers && p.commonDnfTriggers.length > 0) {\n output += `- Common DNF Triggers:\\n`;\n p.commonDnfTriggers.slice(0, 3).forEach(t => {\n output += ` - ${t.trigger} (${t.count}x)\\n`;\n });\n }\n output += '\\n';\n }\n\n // Market\n if (metrics.market) {\n const m = metrics.market;\n output += `### Market Positioning\\n`;\n if (m.avgWordOfMouth) output += `- Word of Mouth Potential: ${m.avgWordOfMouth.toFixed(1)}/10\\n`;\n if (m.topComparableBooks && m.topComparableBooks.length > 0) {\n const books = m.topComparableBooks.slice(0, 3).map(b => b.title).join(', ');\n output += `- Comparable Books: ${books}\\n`;\n }\n output += '\\n';\n }\n\n return output;\n}\n\n/**\n * 格式化單一讀者反饋 (English headers for better AI processing)\n */\nfunction formatIndividualFeedback(feedback: IndividualFeedback): string {\n const name = feedback.personaName || feedback.personaToken;\n let output = `### ${name}\\n\\n`;\n\n // Overall scores\n if (feedback.overall) {\n const o = feedback.overall;\n if (o.continueReading) output += `**Continue Reading Intent**: ${o.continueReading}/10\\n`;\n if (o.recommendation) output += `**Recommendation**: ${o.recommendation}/10\\n`;\n if (o.dnfRisk) output += `**DNF Risk**: ${o.dnfRisk}\\n`;\n output += '\\n';\n }\n\n // Kindle Rating\n if (feedback.kindleRating) {\n output += `**Kindle Rating**: ⭐ ${feedback.kindleRating.score}/5`;\n if (feedback.kindleRating.rationale) {\n output += ` - ${feedback.kindleRating.rationale}`;\n }\n output += '\\n\\n';\n }\n\n // Detailed Feedback\n if (feedback.detailedFeedback) {\n const d = feedback.detailedFeedback;\n\n if (d.whatWorked) {\n output += `**What Worked**:\\n${d.whatWorked}\\n\\n`;\n }\n\n if (d.whatDidntWork) {\n output += `**What Didn't Work**:\\n${d.whatDidntWork}\\n\\n`;\n }\n\n if (d.strongestElement) {\n output += `**Strongest Element**: ${d.strongestElement}\\n`;\n }\n\n if (d.weakestElement) {\n output += `**Weakest Element**: ${d.weakestElement}\\n`;\n }\n\n if (d.wouldYouBuy) {\n output += `**Would You Buy**: ${d.wouldYouBuy}\\n`;\n }\n\n if (d.specificSuggestions && d.specificSuggestions.length > 0) {\n output += `\\n**Specific Suggestions**:\\n`;\n d.specificSuggestions.forEach((s, i) => {\n output += `${i + 1}. ${s}\\n`;\n });\n }\n\n if (d.finalThoughts) {\n output += `\\n**Final Thoughts**:\\n${d.finalThoughts}\\n`;\n }\n }\n\n // Emotional Journey\n if (feedback.emotionalJourney) {\n const e = feedback.emotionalJourney;\n if (e.emotionalArc) {\n output += `\\n**Emotional Arc**: ${e.emotionalArc}\\n`;\n }\n if (e.peakMoments && e.peakMoments.length > 0) {\n const moments = e.peakMoments.map(m =>\n typeof m === 'string' ? m : (m as { moment?: string; description?: string }).moment || (m as { moment?: string; description?: string }).description || JSON.stringify(m)\n );\n output += `**Peak Moments**: ${moments.join(', ')}\\n`;\n }\n if (e.overallMood) {\n output += `**Overall Mood**: ${e.overallMood}\\n`;\n }\n }\n\n return output;\n}\n\n/**\n * 在 snapshot 中尋找檔案(複製自 content.ts)\n */\nfunction findFileInSnapshot(\n files: FileSnapshot[],\n path: string\n): FileSnapshot | null {\n const normalizedPath = path.replace(/^\\//, '').toLowerCase();\n const pathParts = normalizedPath.split('/');\n\n function search(\n items: FileSnapshot[],\n remainingParts: string[]\n ): FileSnapshot | null {\n for (const item of items) {\n const itemNameLower = item.name.toLowerCase();\n const itemTokenLower = item.token.toLowerCase();\n\n if (remainingParts.length === 1) {\n const target = remainingParts[0];\n if (\n itemNameLower === target ||\n itemTokenLower === target ||\n itemNameLower.replace(/\\.[^.]+$/, '') === target.replace(/\\.[^.]+$/, '')\n ) {\n return item;\n }\n }\n\n if (item.kind === 'folder' && item.children) {\n if (\n itemNameLower === remainingParts[0] ||\n itemTokenLower === remainingParts[0]\n ) {\n const result = search(item.children, remainingParts.slice(1));\n if (result) return result;\n }\n\n const result = search(item.children, remainingParts);\n if (result) return result;\n }\n }\n\n return null;\n }\n\n let result = search(files, pathParts);\n if (result) return result;\n\n result = searchByName(files, pathParts[pathParts.length - 1]);\n return result;\n}\n\nfunction searchByName(\n files: FileSnapshot[],\n name: string\n): FileSnapshot | null {\n const nameLower = name.toLowerCase();\n\n for (const item of files) {\n const itemNameLower = item.name.toLowerCase();\n const itemTokenLower = item.token.toLowerCase();\n\n if (\n itemNameLower === nameLower ||\n itemTokenLower === nameLower ||\n itemNameLower.replace(/\\.[^.]+$/, '') === nameLower.replace(/\\.[^.]+$/, '')\n ) {\n return item;\n }\n\n if (item.kind === 'folder' && item.children) {\n const result = searchByName(item.children, name);\n if (result) return result;\n }\n }\n\n return null;\n}\n","/**\n * MCP File Operations Tools\n *\n * Provides tools for AI to read, write, create, delete, and search files in books.\n */\n\nimport { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { SlimaApiClient } from '../api/client.js';\nimport { formatErrorForMcp } from '../utils/errors.js';\n\n/**\n * Register file operation tools\n */\nexport function registerFileTools(\n server: McpServer,\n client: SlimaApiClient\n): void {\n // === read_file ===\n server.tool(\n 'read_file',\n 'Read the content of any file in a book by its path',\n {\n book_token: z.string().describe('Book token (e.g., bk_abc123)'),\n path: z.string().describe('File path (e.g., \"characters/protagonist.md\" or \"chapter-01.md\")'),\n },\n async ({ book_token, path }) => {\n try {\n const result = await client.readFile(book_token, path);\n\n const fileInfo = [\n `# ${result.file.name}`,\n '',\n `**Path:** ${result.file.path}`,\n `**Words:** ${result.file.wordCount}`,\n `**Type:** ${result.file.fileType || 'unknown'}`,\n '',\n '---',\n '',\n result.content || '(empty file)',\n ].join('\\n');\n\n return {\n content: [{ type: 'text', text: fileInfo }],\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: formatErrorForMcp(error) }],\n isError: true,\n };\n }\n }\n );\n\n // === write_file ===\n server.tool(\n 'write_file',\n 'Replace the entire content of an existing file (creates a new commit)',\n {\n book_token: z.string().describe('Book token (e.g., bk_abc123)'),\n path: z.string().describe('File path (e.g., \"characters/protagonist.md\")'),\n content: z.string().describe('New content to write'),\n commit_message: z.string().optional().describe('Commit message (optional, auto-generated if not provided)'),\n },\n async ({ book_token, path, content, commit_message }) => {\n try {\n const result = await client.updateFile(book_token, {\n path,\n content,\n commitMessage: commit_message,\n });\n\n return {\n content: [\n {\n type: 'text',\n text: `File updated successfully.\\n\\nCommit: ${result.commit.token}\\nMessage: ${result.commit.name || result.commit.message}`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: formatErrorForMcp(error) }],\n isError: true,\n };\n }\n }\n );\n\n // === create_file ===\n server.tool(\n 'create_file',\n 'Create a new file in a book (creates a new commit)',\n {\n book_token: z.string().describe('Book token (e.g., bk_abc123)'),\n path: z.string().describe('File path including parent folders (e.g., \"characters/new-character.md\")'),\n content: z.string().optional().describe('Initial content (optional, defaults to empty)'),\n commit_message: z.string().optional().describe('Commit message (optional, auto-generated if not provided)'),\n },\n async ({ book_token, path, content, commit_message }) => {\n try {\n const result = await client.createFile(book_token, {\n path,\n content: content || '',\n commitMessage: commit_message,\n });\n\n return {\n content: [\n {\n type: 'text',\n text: `File created successfully.\\n\\nFile Token: ${result.fileToken}\\nCommit: ${result.commit.token}\\nMessage: ${result.commit.name || result.commit.message}`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: formatErrorForMcp(error) }],\n isError: true,\n };\n }\n }\n );\n\n // === delete_file ===\n server.tool(\n 'delete_file',\n 'Delete a file from a book (creates a new commit)',\n {\n book_token: z.string().describe('Book token (e.g., bk_abc123)'),\n path: z.string().describe('File path to delete (e.g., \"old-notes.md\")'),\n commit_message: z.string().optional().describe('Commit message (optional, auto-generated if not provided)'),\n },\n async ({ book_token, path, commit_message }) => {\n try {\n const result = await client.deleteFile(book_token, {\n path,\n commitMessage: commit_message,\n });\n\n return {\n content: [\n {\n type: 'text',\n text: `File deleted successfully.\\n\\nCommit: ${result.commit.token}\\nMessage: ${result.commit.name || result.commit.message}`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: formatErrorForMcp(error) }],\n isError: true,\n };\n }\n }\n );\n\n // === append_to_file ===\n server.tool(\n 'append_to_file',\n 'Append content to the end of an existing file (creates a new commit)',\n {\n book_token: z.string().describe('Book token (e.g., bk_abc123)'),\n path: z.string().describe('File path (e.g., \"notes.md\")'),\n content: z.string().describe('Content to append'),\n commit_message: z.string().optional().describe('Commit message (optional, auto-generated if not provided)'),\n },\n async ({ book_token, path, content, commit_message }) => {\n try {\n const result = await client.appendToFile(book_token, {\n path,\n content,\n commitMessage: commit_message,\n });\n\n return {\n content: [\n {\n type: 'text',\n text: `Content appended successfully.\\n\\nCommit: ${result.commit.token}\\nMessage: ${result.commit.name || result.commit.message}`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: formatErrorForMcp(error) }],\n isError: true,\n };\n }\n }\n );\n\n // === search_content ===\n server.tool(\n 'search_content',\n 'Search for content across all files in a book',\n {\n book_token: z.string().describe('Book token (e.g., bk_abc123)'),\n query: z.string().describe('Search query (e.g., \"blue eyes\" or \"protagonist name\")'),\n file_types: z.array(z.string()).optional().describe('Filter by file types (e.g., [\"markdown\", \"txt\"])'),\n limit: z.number().optional().describe('Maximum number of matches to return (default: 20)'),\n },\n async ({ book_token, query, file_types, limit }) => {\n try {\n const result = await client.searchFiles(book_token, {\n query,\n fileTypes: file_types,\n limit,\n });\n\n if (result.matches.length === 0) {\n return {\n content: [\n {\n type: 'text',\n text: `No matches found for \"${query}\".`,\n },\n ],\n };\n }\n\n const output: string[] = [\n `# Search Results for \"${query}\"`,\n '',\n `Found ${result.matches.length} file(s) with matches:`,\n '',\n ];\n\n for (const match of result.matches) {\n output.push(`## ${match.file.path}`);\n output.push(`Words: ${match.file.wordCount} | Matches: ${match.matchCount}`);\n output.push('');\n\n for (const snippet of match.snippets) {\n output.push(`> ${snippet.text}`);\n output.push('');\n }\n }\n\n return {\n content: [{ type: 'text', text: output.join('\\n') }],\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: formatErrorForMcp(error) }],\n isError: true,\n };\n }\n }\n );\n}\n","/**\n * Token Storage Utility\n *\n * 將 API Token 儲存在使用者的 home 目錄下\n * ~/.slima/credentials.json\n */\n\nimport { promises as fs } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nconst SLIMA_DIR = '.slima';\nconst CREDENTIALS_FILE = 'credentials.json';\n\ninterface Credentials {\n apiToken: string;\n createdAt: string;\n baseUrl?: string;\n}\n\nfunction getCredentialsPath(): string {\n return join(homedir(), SLIMA_DIR, CREDENTIALS_FILE);\n}\n\nfunction getSlimaDir(): string {\n return join(homedir(), SLIMA_DIR);\n}\n\n/**\n * 儲存 API Token\n */\nexport async function saveToken(apiToken: string, baseUrl?: string): Promise<void> {\n const slimaDir = getSlimaDir();\n\n // 確保目錄存在\n await fs.mkdir(slimaDir, { recursive: true });\n\n const credentials: Credentials = {\n apiToken,\n createdAt: new Date().toISOString(),\n ...(baseUrl && { baseUrl }),\n };\n\n const credentialsPath = getCredentialsPath();\n await fs.writeFile(credentialsPath, JSON.stringify(credentials, null, 2), 'utf-8');\n\n // 設定檔案權限為 600(僅擁有者可讀寫)\n await fs.chmod(credentialsPath, 0o600);\n}\n\n/**\n * 讀取 API Token\n */\nexport async function loadToken(): Promise<Credentials | null> {\n try {\n const credentialsPath = getCredentialsPath();\n const content = await fs.readFile(credentialsPath, 'utf-8');\n return JSON.parse(content) as Credentials;\n } catch {\n return null;\n }\n}\n\n/**\n * 刪除 API Token\n */\nexport async function deleteToken(): Promise<void> {\n try {\n const credentialsPath = getCredentialsPath();\n await fs.unlink(credentialsPath);\n } catch {\n // 檔案不存在,忽略\n }\n}\n\n/**\n * 檢查是否已認證\n */\nexport async function isAuthenticated(): Promise<boolean> {\n const credentials = await loadToken();\n return credentials !== null && !!credentials.apiToken;\n}\n\n/**\n * 取得 credentials 檔案路徑(供顯示用)\n */\nexport function getCredentialsFilePath(): string {\n return getCredentialsPath();\n}\n","/**\n * CLI Auth Command\n *\n * 實作類似 Claude Code / GitHub CLI 的認證流程:\n * 1. 使用者執行 `slima-mcp auth`\n * 2. 開啟瀏覽器到 Slima 認證頁面\n * 3. 使用者登入並授權\n * 4. 本地伺服器接收 callback 並儲存 token\n */\n\nimport { createServer, type IncomingMessage, type ServerResponse } from 'node:http';\nimport { URL } from 'node:url';\nimport { randomBytes } from 'node:crypto';\nimport { saveToken, loadToken, deleteToken, getCredentialsFilePath } from '../utils/token-storage.js';\n\n// 認證使用 API 伺服器(處理 OAuth 和 session)\nconst DEFAULT_API_URL = 'https://api.slima.ai';\nconst CALLBACK_PORT_START = 8765;\nconst CALLBACK_PORT_END = 8775;\n\n/**\n * 開啟瀏覽器\n */\nasync function openBrowser(url: string): Promise<void> {\n const { exec } = await import('node:child_process');\n const { promisify } = await import('node:util');\n const execAsync = promisify(exec);\n\n const platform = process.platform;\n\n try {\n if (platform === 'darwin') {\n await execAsync(`open \"${url}\"`);\n } else if (platform === 'win32') {\n await execAsync(`start \"\" \"${url}\"`);\n } else {\n // Linux / WSL\n // 嘗試多個可能的命令\n const commands = ['xdg-open', 'sensible-browser', 'wslview'];\n for (const cmd of commands) {\n try {\n await execAsync(`${cmd} \"${url}\"`);\n return;\n } catch {\n // 繼續嘗試下一個\n }\n }\n // 如果都失敗,顯示 URL 讓使用者手動開啟\n console.log(`\\nPlease open this URL in your browser:\\n${url}\\n`);\n }\n } catch {\n console.log(`\\nPlease open this URL in your browser:\\n${url}\\n`);\n }\n}\n\n/**\n * 尋找可用的 port\n */\nasync function findAvailablePort(): Promise<number> {\n for (let port = CALLBACK_PORT_START; port <= CALLBACK_PORT_END; port++) {\n const available = await isPortAvailable(port);\n if (available) {\n return port;\n }\n }\n throw new Error(`No available ports between ${CALLBACK_PORT_START} and ${CALLBACK_PORT_END}`);\n}\n\nfunction isPortAvailable(port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const server = createServer();\n server.once('error', () => resolve(false));\n server.once('listening', () => {\n server.close(() => resolve(true));\n });\n server.listen(port, '127.0.0.1');\n });\n}\n\n/**\n * 產生隨機 state(防止 CSRF)\n */\nfunction generateState(): string {\n return randomBytes(16).toString('hex');\n}\n\n/**\n * 成功頁面 HTML\n */\nfunction getSuccessHtml(): string {\n return `<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\">\n <title>Slima MCP - Authenticated</title>\n <style>\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n display: flex;\n justify-content: center;\n align-items: center;\n height: 100vh;\n margin: 0;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n }\n .container {\n text-align: center;\n background: white;\n padding: 60px;\n border-radius: 16px;\n box-shadow: 0 20px 60px rgba(0,0,0,0.3);\n }\n .checkmark {\n font-size: 64px;\n margin-bottom: 20px;\n }\n h1 {\n color: #333;\n margin-bottom: 10px;\n }\n p {\n color: #666;\n font-size: 16px;\n }\n .hint {\n margin-top: 20px;\n color: #999;\n font-size: 14px;\n }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"checkmark\">✅</div>\n <h1>Authentication Successful!</h1>\n <p>You can now close this window and return to your terminal.</p>\n <p class=\"hint\">Slima MCP is ready to use.</p>\n </div>\n</body>\n</html>`;\n}\n\n/**\n * 錯誤頁面 HTML\n */\n/**\n * HTML escape to prevent XSS\n */\nfunction escapeHtml(text: string): string {\n const map: Record<string, string> = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#039;',\n };\n return text.replace(/[&<>\"']/g, (char) => map[char]);\n}\n\n/**\n * 錯誤頁面 HTML\n */\nfunction getErrorHtml(message: string): string {\n const safeMessage = escapeHtml(message);\n return `<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\">\n <title>Slima MCP - Error</title>\n <style>\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n display: flex;\n justify-content: center;\n align-items: center;\n height: 100vh;\n margin: 0;\n background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);\n }\n .container {\n text-align: center;\n background: white;\n padding: 60px;\n border-radius: 16px;\n box-shadow: 0 20px 60px rgba(0,0,0,0.3);\n }\n .error-icon {\n font-size: 64px;\n margin-bottom: 20px;\n }\n h1 {\n color: #e74c3c;\n margin-bottom: 10px;\n }\n p {\n color: #666;\n font-size: 16px;\n }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"error-icon\">❌</div>\n <h1>Authentication Failed</h1>\n <p>${safeMessage}</p>\n </div>\n</body>\n</html>`;\n}\n\n/**\n * 執行認證流程\n */\nexport async function runAuth(options: { baseUrl?: string } = {}): Promise<void> {\n const baseUrl = options.baseUrl || process.env.SLIMA_API_URL || DEFAULT_API_URL;\n\n console.log('\\n🔐 Slima MCP Authentication\\n');\n\n // 檢查是否已經認證\n const existingCredentials = await loadToken();\n if (existingCredentials) {\n console.log('You are already authenticated.');\n console.log(`Token stored at: ${getCredentialsFilePath()}`);\n console.log('\\nTo re-authenticate, first run: slima-mcp logout\\n');\n return;\n }\n\n const state = generateState();\n const port = await findAvailablePort();\n\n console.log('Starting local server for authentication callback...');\n\n // 建立本地伺服器接收 callback\n const tokenPromise = new Promise<string>((resolve, reject) => {\n const server = createServer((req: IncomingMessage, res: ServerResponse) => {\n const url = new URL(req.url || '/', `http://localhost:${port}`);\n\n if (url.pathname === '/callback') {\n const token = url.searchParams.get('token');\n const returnedState = url.searchParams.get('state');\n const error = url.searchParams.get('error');\n\n if (error) {\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(getErrorHtml(error));\n server.close();\n reject(new Error(error));\n return;\n }\n\n if (returnedState !== state) {\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(getErrorHtml('Invalid state parameter. Please try again.'));\n server.close();\n reject(new Error('State mismatch'));\n return;\n }\n\n if (!token) {\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(getErrorHtml('No token received. Please try again.'));\n server.close();\n reject(new Error('No token received'));\n return;\n }\n\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(getSuccessHtml());\n server.close();\n resolve(token);\n } else {\n res.writeHead(404);\n res.end('Not found');\n }\n });\n\n server.listen(port, '127.0.0.1', () => {\n console.log(`Listening on http://127.0.0.1:${port}`);\n });\n\n // 30 秒超時\n setTimeout(() => {\n server.close();\n reject(new Error('Authentication timed out. Please try again.'));\n }, 30000);\n });\n\n // 建立認證 URL(使用 API endpoint)\n const authUrl = `${baseUrl}/api/v1/auth/cli?state=${state}&callback_port=${port}`;\n\n console.log('\\nOpening browser for authentication...');\n await openBrowser(authUrl);\n\n console.log('\\nWaiting for authentication...');\n console.log('(Press Ctrl+C to cancel)\\n');\n\n try {\n const token = await tokenPromise;\n await saveToken(token, baseUrl !== DEFAULT_API_URL ? baseUrl : undefined);\n\n console.log('\\n✅ Authentication successful!');\n console.log(`Token saved to: ${getCredentialsFilePath()}`);\n console.log('\\nYou can now use Slima MCP with any MCP-compatible AI tool.\\n');\n } catch (error) {\n console.error('\\n❌ Authentication failed:', error instanceof Error ? error.message : error);\n process.exit(1);\n }\n}\n\n/**\n * 登出(刪除 token)\n */\nexport async function runLogout(): Promise<void> {\n console.log('\\n🔓 Slima MCP Logout\\n');\n\n const credentials = await loadToken();\n if (!credentials) {\n console.log('You are not authenticated.\\n');\n return;\n }\n\n await deleteToken();\n console.log('✅ Successfully logged out.');\n console.log(`Removed credentials from: ${getCredentialsFilePath()}\\n`);\n}\n\n/**\n * 顯示目前狀態\n */\nexport async function runStatus(): Promise<void> {\n console.log('\\n📊 Slima MCP Status\\n');\n\n const credentials = await loadToken();\n if (!credentials) {\n console.log('Status: Not authenticated');\n console.log('\\nRun `slima-mcp auth` to authenticate.\\n');\n return;\n }\n\n console.log('Status: Authenticated');\n console.log(`Token: ${credentials.apiToken.substring(0, 15)}...`);\n console.log(`Authenticated at: ${credentials.createdAt}`);\n if (credentials.baseUrl) {\n console.log(`API URL: ${credentials.baseUrl}`);\n }\n console.log(`Credentials file: ${getCredentialsFilePath()}\\n`);\n}\n"],"mappings":"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","names":["z","z","result","z","z","findFileInSnapshot","result","searchByName","z","z"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/server.ts","../src/utils/errors.ts","../src/utils/logger.ts","../src/api/client.ts","../src/tools/books.ts","../src/tools/content.ts","../src/tools/beta-reader.ts","../src/tools/files.ts","../src/utils/token-storage.ts","../src/cli/auth.ts"],"sourcesContent":["/**\n * Slima MCP Server - CLI Entry Point\n *\n * Usage:\n * slima-mcp - Start MCP server (requires SLIMA_API_TOKEN or prior auth)\n * slima-mcp auth - Authenticate with Slima (opens browser)\n * slima-mcp logout - Remove saved credentials\n * slima-mcp status - Show authentication status\n * slima-mcp --help - Show help\n */\n\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { createSlimaServer } from './server.js';\nimport { logger } from './utils/logger.js';\nimport { loadToken, getCredentialsFilePath } from './utils/token-storage.js';\nimport { runAuth, runLogout, runStatus } from './cli/auth.js';\n\ndeclare const __VERSION__: string;\nconst VERSION = __VERSION__;\n\nfunction showHelp(): void {\n console.log(`\nSlima MCP v${VERSION}\nMCP Server for Slima - AI Writing IDE for Novel Authors\n\nUSAGE:\n slima-mcp [command]\n\nCOMMANDS:\n (none) Start the MCP server\n auth Authenticate with Slima (opens browser)\n logout Remove saved credentials\n status Show authentication status\n --help Show this help message\n --version Show version\n\nAUTHENTICATION:\n 1. Run: slima-mcp auth\n 2. Complete authentication in browser\n 3. Token is automatically saved\n\n Or set SLIMA_API_TOKEN environment variable.\n\nEXAMPLES:\n slima-mcp auth # Authenticate with browser\n slima-mcp status # Check auth status\n SLIMA_API_TOKEN=xxx slima-mcp # Use env var\n\nCONFIGURATION (for AI tools):\n Claude Desktop, Cursor, etc.:\n {\n \"mcpServers\": {\n \"slima\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"slima-mcp\"]\n }\n }\n }\n\nMORE INFO:\n https://github.com/slima-ai/slima-mcp\n`);\n}\n\nfunction showVersion(): void {\n console.log(`slima-mcp v${VERSION}`);\n}\n\nasync function startServer(): Promise<void> {\n // 優先使用環境變數,否則使用儲存的 token\n let apiToken = process.env.SLIMA_API_TOKEN;\n let baseUrl = process.env.SLIMA_API_URL;\n\n if (!apiToken) {\n const credentials = await loadToken();\n if (credentials) {\n apiToken = credentials.apiToken;\n baseUrl = baseUrl || credentials.baseUrl;\n }\n }\n\n if (!apiToken) {\n logger.error('Not authenticated and SLIMA_API_TOKEN not set');\n logger.error('');\n logger.error('To authenticate, run:');\n logger.error(' slima-mcp auth');\n logger.error('');\n logger.error('Or set environment variable:');\n logger.error(' SLIMA_API_TOKEN=your_token slima-mcp');\n logger.error('');\n logger.error('Get your API token from: https://app.slima.ai/settings/api-tokens');\n process.exit(1);\n }\n\n try {\n const server = createSlimaServer({\n apiToken,\n baseUrl,\n });\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n logger.info('Slima MCP Server running on stdio');\n\n // 優雅關閉\n process.on('SIGINT', async () => {\n logger.info('Shutting down...');\n await server.close();\n process.exit(0);\n });\n\n process.on('SIGTERM', async () => {\n logger.info('Shutting down...');\n await server.close();\n process.exit(0);\n });\n } catch (error) {\n logger.error('Failed to start server', error);\n process.exit(1);\n }\n}\n\nasync function main(): Promise<void> {\n const args = process.argv.slice(2);\n const command = args[0];\n\n switch (command) {\n case 'auth':\n await runAuth();\n break;\n\n case 'logout':\n await runLogout();\n break;\n\n case 'status':\n await runStatus();\n break;\n\n case '--help':\n case '-h':\n case 'help':\n showHelp();\n break;\n\n case '--version':\n case '-v':\n showVersion();\n break;\n\n case undefined:\n // 預設:啟動 MCP server\n await startServer();\n break;\n\n default:\n console.error(`Unknown command: ${command}`);\n console.error('Run `slima-mcp --help` for usage.');\n process.exit(1);\n }\n}\n\nmain();\n","/**\n * Slima MCP Server\n */\n\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { SlimaApiClient } from './api/client.js';\nimport { registerBookTools } from './tools/books.js';\nimport { registerContentTools } from './tools/content.js';\nimport { registerBetaReaderTools } from './tools/beta-reader.js';\nimport { registerFileTools } from './tools/files.js';\nimport { logger } from './utils/logger.js';\n\ndeclare const __VERSION__: string;\n\nexport interface ServerConfig {\n apiToken: string;\n baseUrl?: string;\n}\n\n/**\n * 建立 Slima MCP Server\n */\nexport function createSlimaServer(config: ServerConfig): McpServer {\n const client = new SlimaApiClient({\n token: config.apiToken,\n baseUrl: config.baseUrl || 'https://api.slima.ai',\n });\n\n const server = new McpServer({\n name: 'slima',\n version: __VERSION__,\n });\n\n // 註冊工具\n registerBookTools(server, client);\n registerContentTools(server, client);\n registerBetaReaderTools(server, client);\n registerFileTools(server, client);\n\n logger.info('Slima MCP Server initialized');\n logger.info(`API endpoint: ${config.baseUrl || 'https://api.slima.ai'}`);\n\n return server;\n}\n","/**\n * 錯誤處理工具\n */\n\nexport class SlimaApiError extends Error {\n constructor(\n public status: number,\n public code?: string,\n message?: string\n ) {\n super(message || `API Error: ${status}`);\n this.name = 'SlimaApiError';\n }\n}\n\nexport class AuthenticationError extends SlimaApiError {\n constructor(message = 'Invalid or expired API token') {\n super(401, 'UNAUTHORIZED', message);\n this.name = 'AuthenticationError';\n }\n}\n\nexport class NotFoundError extends SlimaApiError {\n constructor(resource = 'Resource') {\n super(404, 'NOT_FOUND', `${resource} not found`);\n this.name = 'NotFoundError';\n }\n}\n\nexport class InsufficientCreditsError extends SlimaApiError {\n constructor() {\n super(402, 'INSUFFICIENT_CREDITS', 'Insufficient credits');\n this.name = 'InsufficientCreditsError';\n }\n}\n\n/**\n * 格式化錯誤訊息供 MCP 回傳\n */\nexport function formatErrorForMcp(error: unknown): string {\n if (error instanceof SlimaApiError) {\n switch (error.code) {\n case 'NOT_FOUND':\n return 'Resource not found. Please check the token.';\n case 'UNAUTHORIZED':\n return 'Invalid API token. Please check your configuration.';\n case 'INSUFFICIENT_CREDITS':\n return 'Insufficient credits. Please top up your account.';\n case 'TOKEN_EXPIRED':\n return 'API token has expired. Please generate a new one.';\n case 'TOKEN_REVOKED':\n return 'API token has been revoked. Please generate a new one.';\n default:\n return error.message;\n }\n }\n\n if (error instanceof Error) {\n return error.message;\n }\n\n return 'An unexpected error occurred.';\n}\n","/**\n * Logger 工具\n *\n * 重要:MCP STDIO 模式下,stdout 是協議通道,\n * 所有日誌必須輸出到 stderr\n */\n\nconst isDebug = process.env.DEBUG === 'true' || process.env.DEBUG === '1';\n\nexport const logger = {\n info: (message: string, ...args: unknown[]) => {\n console.error(`[INFO] ${message}`, ...args);\n },\n\n warn: (message: string, ...args: unknown[]) => {\n console.error(`[WARN] ${message}`, ...args);\n },\n\n error: (message: string, error?: unknown) => {\n if (error instanceof Error) {\n console.error(`[ERROR] ${message}:`, error.message);\n if (isDebug && error.stack) {\n console.error(error.stack);\n }\n } else if (error !== undefined) {\n console.error(`[ERROR] ${message}:`, error);\n } else {\n console.error(`[ERROR] ${message}`);\n }\n },\n\n debug: (message: string, ...args: unknown[]) => {\n if (isDebug) {\n console.error(`[DEBUG] ${message}`, ...args);\n }\n },\n};\n","/**\n * Slima API Client\n */\n\nimport {\n type Book,\n type Commit,\n type Branch,\n type Blob,\n type Persona,\n type ReaderTest,\n type ReaderTestProgress,\n type CreateReaderTestParams,\n type ApiResponse,\n type ApiError,\n type CommitsListResponse,\n type BlobsDownloadResponse,\n type McpFileReadResponse,\n type McpFileCreateResponse,\n type McpFileUpdateResponse,\n type McpFileDeleteResponse,\n type McpFileAppendResponse,\n type McpSearchResponse,\n} from './types.js';\nimport {\n SlimaApiError,\n AuthenticationError,\n NotFoundError,\n InsufficientCreditsError,\n} from '../utils/errors.js';\nimport { logger } from '../utils/logger.js';\n\nexport interface SlimaConfig {\n baseUrl: string;\n token: string;\n}\n\nexport class SlimaApiClient {\n private readonly baseUrl: string;\n private readonly token: string;\n\n constructor(config: SlimaConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, ''); // 移除尾部斜線\n this.token = config.token;\n }\n\n /**\n * 發送 API 請求\n */\n private async request<T>(\n method: string,\n path: string,\n body?: unknown\n ): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n logger.debug(`${method} ${path}`);\n\n const response = await fetch(url, {\n method,\n headers: {\n Authorization: `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n 'User-Agent': 'slima-mcp-server/0.1.0',\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n await this.handleErrorResponse(response);\n }\n\n const json = (await response.json()) as ApiResponse<T>;\n return json.data;\n }\n\n /**\n * 處理錯誤回應\n */\n private async handleErrorResponse(response: Response): Promise<never> {\n let errorData: ApiError | undefined;\n\n try {\n errorData = (await response.json()) as ApiError;\n } catch {\n // 無法解析 JSON\n }\n\n const code = errorData?.error?.code;\n const message = errorData?.error?.message;\n\n switch (response.status) {\n case 401:\n throw new AuthenticationError(message);\n case 404:\n throw new NotFoundError(message);\n case 402:\n throw new InsufficientCreditsError();\n default:\n throw new SlimaApiError(response.status, code, message);\n }\n }\n\n // === 書籍相關 ===\n\n /**\n * 列出所有書籍\n */\n async listBooks(): Promise<Book[]> {\n return this.request<Book[]>('GET', '/api/v1/books');\n }\n\n /**\n * 取得書籍詳情\n */\n async getBook(token: string): Promise<Book> {\n return this.request<Book>('GET', `/api/v1/books/${token}`);\n }\n\n /**\n * 建立新書籍\n */\n async createBook(params: {\n title: string;\n authorName?: string;\n description?: string;\n }): Promise<Book> {\n return this.request<Book>('POST', '/api/v1/books', {\n book: {\n title: params.title,\n author_name: params.authorName,\n description: params.description,\n },\n });\n }\n\n // === 版本控制相關 ===\n\n /**\n * 列出 Commits\n * 注意:API 回傳 { commits: [...] },需要解構\n */\n async listCommits(bookToken: string, limit = 10): Promise<Commit[]> {\n const response = await this.request<CommitsListResponse>(\n 'GET',\n `/api/v1/books/${bookToken}/commits?limit=${limit}`\n );\n return response.commits;\n }\n\n /**\n * 取得 Commit 詳情\n */\n async getCommit(bookToken: string, commitToken: string): Promise<Commit> {\n return this.request<Commit>(\n 'GET',\n `/api/v1/books/${bookToken}/commits/${commitToken}`\n );\n }\n\n /**\n * 列出分支\n */\n async listBranches(bookToken: string): Promise<Branch[]> {\n return this.request<Branch[]>('GET', `/api/v1/books/${bookToken}/branches`);\n }\n\n /**\n * 下載 Blobs\n * 注意:API 回傳 { blobs: [...], notFound: [...], truncated: ... }\n */\n async downloadBlobs(bookToken: string, hashes: string[]): Promise<Blob[]> {\n const response = await this.request<BlobsDownloadResponse>(\n 'POST',\n `/api/v1/books/${bookToken}/blobs/download`,\n { hashes }\n );\n return response.blobs;\n }\n\n // === Persona 相關 ===\n\n /**\n * 列出所有 Personas\n */\n async listPersonas(genre?: string): Promise<Persona[]> {\n const params = genre ? `?genre=${encodeURIComponent(genre)}` : '';\n return this.request<Persona[]>('GET', `/api/v1/personas${params}`);\n }\n\n /**\n * 取得 Persona 詳情\n */\n async getPersona(token: string): Promise<Persona> {\n return this.request<Persona>('GET', `/api/v1/personas/${token}`);\n }\n\n // === Reader Test 相關 ===\n\n /**\n * 建立 Reader Test\n */\n async createReaderTest(\n bookToken: string,\n params: CreateReaderTestParams\n ): Promise<ReaderTest> {\n return this.request<ReaderTest>(\n 'POST',\n `/api/v1/books/${bookToken}/reader_tests`,\n {\n reader_test: {\n report_type: params.reportType || 'chapter',\n persona_tokens: params.personaTokens,\n commit_token: params.commitToken,\n model: params.model,\n scope_config: params.scopeConfig,\n },\n content: params.content,\n }\n );\n }\n\n /**\n * 取得 Reader Test 進度\n */\n async getReaderTestProgress(\n bookToken: string,\n testToken: string\n ): Promise<ReaderTestProgress> {\n return this.request<ReaderTestProgress>(\n 'GET',\n `/api/v1/books/${bookToken}/reader_tests/${testToken}/progress`\n );\n }\n\n /**\n * 取得 Reader Test 結果\n */\n async getReaderTest(bookToken: string, testToken: string): Promise<ReaderTest> {\n return this.request<ReaderTest>(\n 'GET',\n `/api/v1/books/${bookToken}/reader_tests/${testToken}`\n );\n }\n\n // === MCP File Operations ===\n\n /**\n * 讀取檔案內容\n */\n async readFile(bookToken: string, path: string): Promise<McpFileReadResponse> {\n return this.request<McpFileReadResponse>(\n 'POST',\n `/api/v1/books/${bookToken}/mcp/files/read`,\n { path }\n );\n }\n\n /**\n * 建立新檔案\n */\n async createFile(\n bookToken: string,\n params: { path: string; content?: string; parentPath?: string; commitMessage?: string }\n ): Promise<McpFileCreateResponse> {\n return this.request<McpFileCreateResponse>(\n 'POST',\n `/api/v1/books/${bookToken}/mcp/files/create`,\n {\n path: params.path,\n content: params.content || '',\n parent_path: params.parentPath,\n commit_message: params.commitMessage,\n }\n );\n }\n\n /**\n * 更新(覆寫)檔案內容\n */\n async updateFile(\n bookToken: string,\n params: { path: string; content: string; commitMessage?: string }\n ): Promise<McpFileUpdateResponse> {\n return this.request<McpFileUpdateResponse>(\n 'POST',\n `/api/v1/books/${bookToken}/mcp/files/update`,\n {\n path: params.path,\n content: params.content,\n commit_message: params.commitMessage,\n }\n );\n }\n\n /**\n * 刪除檔案\n */\n async deleteFile(\n bookToken: string,\n params: { path: string; commitMessage?: string }\n ): Promise<McpFileDeleteResponse> {\n return this.request<McpFileDeleteResponse>(\n 'POST',\n `/api/v1/books/${bookToken}/mcp/files/delete`,\n {\n path: params.path,\n commit_message: params.commitMessage,\n }\n );\n }\n\n /**\n * 附加內容到檔案\n */\n async appendToFile(\n bookToken: string,\n params: { path: string; content: string; commitMessage?: string }\n ): Promise<McpFileAppendResponse> {\n return this.request<McpFileAppendResponse>(\n 'POST',\n `/api/v1/books/${bookToken}/mcp/files/append`,\n {\n path: params.path,\n content: params.content,\n commit_message: params.commitMessage,\n }\n );\n }\n\n /**\n * 搜尋檔案內容\n */\n async searchFiles(\n bookToken: string,\n params: { query: string; fileTypes?: string[]; limit?: number }\n ): Promise<McpSearchResponse> {\n return this.request<McpSearchResponse>(\n 'POST',\n `/api/v1/books/${bookToken}/mcp/files/search`,\n {\n query: params.query,\n file_types: params.fileTypes,\n limit: params.limit,\n }\n );\n }\n}\n","/**\n * 書籍相關 Tools\n */\n\nimport { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { SlimaApiClient } from '../api/client.js';\nimport { formatErrorForMcp } from '../utils/errors.js';\nimport type { FileSnapshot } from '../api/types.js';\n\n/**\n * 註冊書籍相關工具\n */\nexport function registerBookTools(\n server: McpServer,\n client: SlimaApiClient\n): void {\n // === create_book ===\n server.tool(\n 'create_book',\n 'Create a new book in your Slima library',\n {\n title: z.string().describe('Book title (required)'),\n author_name: z.string().optional().describe('Author name (optional)'),\n description: z.string().optional().describe('Book description (optional)'),\n },\n async ({ title, author_name, description }) => {\n try {\n const book = await client.createBook({\n title,\n authorName: author_name,\n description,\n });\n\n return {\n content: [\n {\n type: 'text',\n text: `✅ Book created successfully!\\n\\n- **Title**: ${book.title}\\n- **Token**: ${book.token}\\n- **Author**: ${book.authorName || 'N/A'}\\n\\nYou can now add files using create_file with book_token: ${book.token}`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: formatErrorForMcp(error) }],\n isError: true,\n };\n }\n }\n );\n\n // === list_books ===\n server.tool(\n 'list_books',\n 'List all books in your Slima library',\n {},\n async () => {\n try {\n const books = await client.listBooks();\n\n if (books.length === 0) {\n return {\n content: [\n {\n type: 'text',\n text: 'No books found in your library.',\n },\n ],\n };\n }\n\n const formatted = books\n .map((book) => {\n const words = book.totalWordCount?.toLocaleString() || '0';\n return `- **${book.title}** (${book.token})\\n Author: ${book.authorName || 'N/A'} | Words: ${words}`;\n })\n .join('\\n\\n');\n\n return {\n content: [\n {\n type: 'text',\n text: `Found ${books.length} book(s):\\n\\n${formatted}`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: formatErrorForMcp(error) }],\n isError: true,\n };\n }\n }\n );\n\n // === get_book ===\n server.tool(\n 'get_book',\n 'Get details of a specific book',\n {\n book_token: z.string().describe('Book token (e.g., bk_abc123)'),\n },\n async ({ book_token }) => {\n try {\n const book = await client.getBook(book_token);\n\n const text = `# ${book.title}\n\n- **Token**: ${book.token}\n- **Author**: ${book.authorName || 'N/A'}\n- **Description**: ${book.description || 'N/A'}\n- **Language**: ${book.language || 'N/A'}\n- **Total Words**: ${book.totalWordCount?.toLocaleString() || '0'}\n- **Manuscript Words**: ${book.manuscriptWordCount?.toLocaleString() || '0'}\n- **Created**: ${book.createdAt}\n- **Updated**: ${book.updatedAt}`;\n\n return {\n content: [{ type: 'text', text }],\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: formatErrorForMcp(error) }],\n isError: true,\n };\n }\n }\n );\n\n // === get_book_structure ===\n server.tool(\n 'get_book_structure',\n 'Get the file/folder structure of a book',\n {\n book_token: z.string().describe('Book token'),\n },\n async ({ book_token }) => {\n try {\n const commits = await client.listCommits(book_token, 1);\n\n if (commits.length === 0) {\n return {\n content: [\n {\n type: 'text',\n text: 'No commits found. The book may be empty.',\n },\n ],\n };\n }\n\n const snapshot = commits[0].filesSnapshot;\n const tree = formatFileTree(snapshot);\n\n return {\n content: [\n {\n type: 'text',\n text: `File structure for book ${book_token}:\\n\\n${tree}`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: formatErrorForMcp(error) }],\n isError: true,\n };\n }\n }\n );\n\n // === get_writing_stats ===\n server.tool(\n 'get_writing_stats',\n 'Get writing statistics for a book',\n {\n book_token: z.string().describe('Book token'),\n },\n async ({ book_token }) => {\n try {\n const [book, commits] = await Promise.all([\n client.getBook(book_token),\n client.listCommits(book_token, 10),\n ]);\n\n // 計算最近的寫作進度\n let wordChange = 0;\n if (commits.length > 1) {\n const latest = commits[0].totalWordCount || 0;\n const oldest = commits[commits.length - 1].totalWordCount || 0;\n wordChange = latest - oldest;\n }\n\n const sign = wordChange >= 0 ? '+' : '';\n const progressText =\n commits.length > 1\n ? `${sign}${wordChange.toLocaleString()} words (last ${commits.length} commits)`\n : 'N/A (not enough history)';\n\n const text = `# Writing Stats: ${book.title}\n\n- **Total Words**: ${book.totalWordCount?.toLocaleString() || '0'}\n- **Manuscript Words**: ${book.manuscriptWordCount?.toLocaleString() || '0'}\n- **Recent Progress**: ${progressText}\n- **Commits Analyzed**: ${commits.length}\n- **Language**: ${book.language || 'N/A'}`;\n\n return {\n content: [{ type: 'text', text }],\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: formatErrorForMcp(error) }],\n isError: true,\n };\n }\n }\n );\n}\n\n/**\n * 格式化檔案樹\n */\nfunction formatFileTree(files: FileSnapshot[], indent = 0): string {\n return files\n .sort((a, b) => a.position - b.position)\n .map((f) => {\n const prefix = ' '.repeat(indent);\n const icon = f.kind === 'folder' ? '📁' : '📄';\n const words = f.kind === 'file' && f.wordCount ? ` (${f.wordCount} words)` : '';\n const manuscript = f.isManuscript ? ' [M]' : '';\n let line = `${prefix}${icon} ${f.name}${words}${manuscript}`;\n\n if (f.children && f.children.length > 0) {\n line += '\\n' + formatFileTree(f.children, indent + 1);\n }\n\n return line;\n })\n .join('\\n');\n}\n","/**\n * 內容存取 Tools\n */\n\nimport { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { SlimaApiClient } from '../api/client.js';\nimport { formatErrorForMcp } from '../utils/errors.js';\nimport type { FileSnapshot } from '../api/types.js';\n\n/**\n * 註冊內容存取工具\n */\nexport function registerContentTools(\n server: McpServer,\n client: SlimaApiClient\n): void {\n // === get_chapter ===\n server.tool(\n 'get_chapter',\n 'Read the content of a chapter or file from a book',\n {\n book_token: z.string().describe('Book token (e.g., bk_abc123)'),\n file_path: z.string().describe('File path (e.g., /chapters/01.md or chapter-01)'),\n },\n async ({ book_token, file_path }) => {\n try {\n // 1. 取得最新 commit\n const commits = await client.listCommits(book_token, 1);\n\n if (commits.length === 0) {\n return {\n content: [\n {\n type: 'text',\n text: 'No commits found. The book may be empty.',\n },\n ],\n };\n }\n\n // 2. 在 snapshot 中找到檔案\n const file = findFileInSnapshot(commits[0].filesSnapshot, file_path);\n\n if (!file) {\n // 列出可用的檔案\n const availableFiles = listAllFiles(commits[0].filesSnapshot);\n const fileList = availableFiles.slice(0, 10).join('\\n- ');\n const moreText =\n availableFiles.length > 10\n ? `\\n... and ${availableFiles.length - 10} more files`\n : '';\n\n return {\n content: [\n {\n type: 'text',\n text: `File not found: ${file_path}\\n\\nAvailable files:\\n- ${fileList}${moreText}\\n\\nTip: Use get_book_structure to see the full file tree.`,\n },\n ],\n isError: true,\n };\n }\n\n if (file.kind === 'folder') {\n return {\n content: [\n {\n type: 'text',\n text: `\"${file_path}\" is a folder, not a file. Please specify a file path.`,\n },\n ],\n isError: true,\n };\n }\n\n if (!file.blobHash) {\n return {\n content: [\n {\n type: 'text',\n text: `File \"${file_path}\" has no content (empty file).`,\n },\n ],\n };\n }\n\n // 3. 下載 blob 內容\n const blobs = await client.downloadBlobs(book_token, [file.blobHash]);\n\n if (blobs.length === 0) {\n return {\n content: [\n {\n type: 'text',\n text: 'Could not retrieve file content. The blob may be missing.',\n },\n ],\n isError: true,\n };\n }\n\n const content = blobs[0].content;\n const wordInfo = file.wordCount ? ` (${file.wordCount} words)` : '';\n\n return {\n content: [\n {\n type: 'text',\n text: `# ${file.name}${wordInfo}\\n\\n${content}`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: formatErrorForMcp(error) }],\n isError: true,\n };\n }\n }\n );\n}\n\n/**\n * 在 snapshot 中尋找檔案\n * 支援多種路徑格式:\n * - 完整路徑:/chapters/01.md\n * - 相對路徑:chapters/01.md\n * - 檔名:01.md\n * - Token:chapter-01\n */\nfunction findFileInSnapshot(\n files: FileSnapshot[],\n path: string\n): FileSnapshot | null {\n // 正規化路徑\n const normalizedPath = path.replace(/^\\//, '').toLowerCase();\n const pathParts = normalizedPath.split('/');\n\n // 遞迴搜尋\n function search(\n items: FileSnapshot[],\n remainingParts: string[]\n ): FileSnapshot | null {\n for (const item of items) {\n const itemNameLower = item.name.toLowerCase();\n const itemTokenLower = item.token.toLowerCase();\n\n // 完整路徑匹配\n if (remainingParts.length === 1) {\n const target = remainingParts[0];\n if (\n itemNameLower === target ||\n itemTokenLower === target ||\n itemNameLower.replace(/\\.[^.]+$/, '') === target.replace(/\\.[^.]+$/, '')\n ) {\n return item;\n }\n }\n\n // 資料夾匹配,繼續往下搜尋\n if (item.kind === 'folder' && item.children) {\n if (\n itemNameLower === remainingParts[0] ||\n itemTokenLower === remainingParts[0]\n ) {\n const result = search(item.children, remainingParts.slice(1));\n if (result) return result;\n }\n\n // 也嘗試在子資料夾中直接搜尋\n const result = search(item.children, remainingParts);\n if (result) return result;\n }\n }\n\n return null;\n }\n\n // 先嘗試完整路徑\n let result = search(files, pathParts);\n if (result) return result;\n\n // 再嘗試只用檔名搜尋\n result = searchByName(files, pathParts[pathParts.length - 1]);\n return result;\n}\n\n/**\n * 只用檔名搜尋\n */\nfunction searchByName(\n files: FileSnapshot[],\n name: string\n): FileSnapshot | null {\n const nameLower = name.toLowerCase();\n\n for (const item of files) {\n const itemNameLower = item.name.toLowerCase();\n const itemTokenLower = item.token.toLowerCase();\n\n if (\n itemNameLower === nameLower ||\n itemTokenLower === nameLower ||\n itemNameLower.replace(/\\.[^.]+$/, '') === nameLower.replace(/\\.[^.]+$/, '')\n ) {\n return item;\n }\n\n if (item.kind === 'folder' && item.children) {\n const result = searchByName(item.children, name);\n if (result) return result;\n }\n }\n\n return null;\n}\n\n/**\n * 列出所有檔案路徑\n */\nfunction listAllFiles(files: FileSnapshot[], prefix = ''): string[] {\n const result: string[] = [];\n\n for (const item of files) {\n const path = prefix ? `${prefix}/${item.name}` : item.name;\n\n if (item.kind === 'file') {\n result.push(path);\n } else if (item.children) {\n result.push(...listAllFiles(item.children, path));\n }\n }\n\n return result;\n}\n","/**\n * Beta Reader Tools\n */\n\nimport { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { SlimaApiClient } from '../api/client.js';\nimport { formatErrorForMcp } from '../utils/errors.js';\nimport type { FileSnapshot, ReaderTest, IndividualFeedback, AggregatedMetrics } from '../api/types.js';\nimport { logger } from '../utils/logger.js';\n\n/**\n * 註冊 Beta Reader 工具\n */\nexport function registerBetaReaderTools(\n server: McpServer,\n client: SlimaApiClient\n): void {\n // === list_personas ===\n server.tool(\n 'list_personas',\n 'List available virtual reader personas for beta reading feedback',\n {\n genre: z\n .string()\n .optional()\n .describe('Filter by genre (e.g., fantasy, romance, scifi)'),\n },\n async ({ genre }) => {\n try {\n const personas = await client.listPersonas(genre);\n\n if (personas.length === 0) {\n const genreText = genre ? ` for genre \"${genre}\"` : '';\n return {\n content: [\n {\n type: 'text',\n text: `No personas found${genreText}.`,\n },\n ],\n };\n }\n\n const formatted = personas\n .map((p) => {\n const name = p.displayLabels?.zh || p.displayLabels?.en || p.slug;\n const tags = p.genreTags?.join(', ') || 'General';\n const demo = p.demographics || {};\n const gender = demo.gender || 'N/A';\n const age = demo.ageRange || 'N/A';\n\n return `- **${name}** (\\`${p.token}\\`)\n Gender: ${gender} | Age: ${age}\n Genres: ${tags}`;\n })\n .join('\\n\\n');\n\n return {\n content: [\n {\n type: 'text',\n text: `Available Personas (${personas.length}):\\n\\n${formatted}\\n\\n**Tip**: Use the persona token with \\`analyze_chapter\\` to get feedback from a specific reader.`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: formatErrorForMcp(error) }],\n isError: true,\n };\n }\n }\n );\n\n // === analyze_chapter ===\n server.tool(\n 'analyze_chapter',\n 'Get AI Beta Reader feedback on a chapter from a specific reader persona. This may take a moment to complete.',\n {\n book_token: z.string().describe('Book token (e.g., bk_abc123)'),\n file_path: z.string().describe('Chapter file path (e.g., /chapters/01.md)'),\n persona_token: z\n .string()\n .describe('Persona token (e.g., psn_xxx). Use list_personas to find available personas.'),\n },\n async ({ book_token, file_path, persona_token }) => {\n try {\n // 1. 取得最新 commit 和章節內容\n const commits = await client.listCommits(book_token, 1);\n\n if (commits.length === 0) {\n return {\n content: [\n {\n type: 'text',\n text: 'No commits found. The book may be empty.',\n },\n ],\n isError: true,\n };\n }\n\n // 2. 找到檔案\n const file = findFileInSnapshot(commits[0].filesSnapshot, file_path);\n\n if (!file) {\n return {\n content: [\n {\n type: 'text',\n text: `File not found: ${file_path}. Use get_book_structure to see available files.`,\n },\n ],\n isError: true,\n };\n }\n\n if (!file.blobHash) {\n return {\n content: [\n {\n type: 'text',\n text: `File \"${file_path}\" has no content (empty file).`,\n },\n ],\n isError: true,\n };\n }\n\n // 3. 下載內容\n const blobs = await client.downloadBlobs(book_token, [file.blobHash]);\n\n if (blobs.length === 0) {\n return {\n content: [\n {\n type: 'text',\n text: 'Could not retrieve file content.',\n },\n ],\n isError: true,\n };\n }\n\n const content = blobs[0].content;\n\n // 4. 建立 Reader Test\n logger.info(`Creating reader test for ${file_path} with persona ${persona_token}`);\n\n const test = await client.createReaderTest(book_token, {\n reportType: 'chapter',\n personaTokens: [persona_token],\n commitToken: commits[0].token,\n scopeConfig: { chapters: [file_path] },\n content: content,\n });\n\n // 5. 輪詢等待完成(最多 90 秒)\n const result = await pollForCompletion(\n () => client.getReaderTestProgress(book_token, test.token),\n 90000\n );\n\n if (result.status === 'failed') {\n return {\n content: [\n {\n type: 'text',\n text: 'Analysis failed. Please try again later.',\n },\n ],\n isError: true,\n };\n }\n\n if (result.status !== 'completed') {\n return {\n content: [\n {\n type: 'text',\n text: `Analysis is still in progress. You can check the status later.\\n\\nTest ID: ${test.token}`,\n },\n ],\n };\n }\n\n // 6. 取得完整結果\n const fullResult = await client.getReaderTest(book_token, test.token);\n\n // 7. 格式化反饋\n const feedback = formatBetaReaderFeedback(fullResult, file.name);\n\n return {\n content: [{ type: 'text', text: feedback }],\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: formatErrorForMcp(error) }],\n isError: true,\n };\n }\n }\n );\n}\n\n/**\n * 輪詢等待完成\n */\nasync function pollForCompletion(\n checkFn: () => Promise<{ status: string; progress?: number }>,\n timeoutMs: number\n): Promise<{ status: string }> {\n const startTime = Date.now();\n const pollInterval = 3000; // 3 秒\n\n while (Date.now() - startTime < timeoutMs) {\n const result = await checkFn();\n logger.debug(`Poll status: ${result.status}, progress: ${result.progress || 'N/A'}`);\n\n if (result.status === 'completed' || result.status === 'failed') {\n return result;\n }\n\n await sleep(pollInterval);\n }\n\n return { status: 'timeout' };\n}\n\n/**\n * 睡眠\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * 格式化 Beta Reader 反饋 (English headers for better AI processing)\n */\nfunction formatBetaReaderFeedback(test: ReaderTest, fileName: string): string {\n const feedbacks = test.individualFeedbacks || [];\n const metrics = test.aggregatedMetrics;\n\n if (feedbacks.length === 0 && !metrics) {\n return 'No feedback available.';\n }\n\n let output = `# Beta Reader Feedback: ${fileName}\\n\\n`;\n\n // Aggregated metrics summary\n if (metrics) {\n output += formatAggregatedMetrics(metrics);\n }\n\n // Individual persona feedback\n if (feedbacks.length > 0) {\n output += `\\n---\\n\\n## Individual Reader Feedback\\n\\n`;\n output += feedbacks.map(formatIndividualFeedback).join('\\n---\\n\\n');\n }\n\n return output;\n}\n\n/**\n * 格式化聚合指標 (English headers for better AI processing)\n */\nfunction formatAggregatedMetrics(metrics: AggregatedMetrics): string {\n let output = `## Summary Metrics\\n\\n`;\n\n // Overall\n if (metrics.overall) {\n const o = metrics.overall;\n output += `### Overall Scores\\n`;\n if (o.avgContinueReading) output += `- Continue Reading Intent: ${o.avgContinueReading.toFixed(1)}/10\\n`;\n if (o.avgRecommendation) output += `- Recommendation Score: ${o.avgRecommendation.toFixed(1)}/10\\n`;\n if (o.avgWantMore) output += `- Want More: ${o.avgWantMore.toFixed(1)}/10\\n`;\n if (o.dnfRisk) output += `- DNF Risk: ${o.dnfRisk}\\n`;\n output += '\\n';\n }\n\n // Kindle Rating\n if (metrics.kindleRating) {\n output += `### Predicted Kindle Rating\\n`;\n output += `- Average Score: ⭐ ${metrics.kindleRating.avgScore.toFixed(1)}/5\\n`;\n if (metrics.kindleRating.individualScores) {\n const scores = metrics.kindleRating.individualScores\n .map(s => `${s.personaName || 'Reader'}: ${s.score}/5 (${s.confidence})`)\n .join(', ');\n output += `- Individual Scores: ${scores}\\n`;\n }\n output += '\\n';\n }\n\n // Characters\n if (metrics.characters) {\n const c = metrics.characters;\n output += `### Character Evaluation\\n`;\n if (c.avgProtagonistLikability) output += `- Protagonist Likability: ${c.avgProtagonistLikability.toFixed(1)}/10\\n`;\n if (c.avgMotivationClarity) output += `- Motivation Clarity: ${c.avgMotivationClarity.toFixed(1)}/10\\n`;\n if (c.avgDialogueNaturalness) output += `- Dialogue Naturalness: ${c.avgDialogueNaturalness.toFixed(1)}/10\\n`;\n output += '\\n';\n }\n\n // Pacing\n if (metrics.pacing) {\n const p = metrics.pacing;\n output += `### Pacing Evaluation\\n`;\n if (p.avgOverall) output += `- Overall Pacing: ${p.avgOverall.toFixed(1)}/10\\n`;\n if (p.consensus) output += `- Consensus: ${p.consensus}\\n`;\n if (p.commonDnfTriggers && p.commonDnfTriggers.length > 0) {\n output += `- Common DNF Triggers:\\n`;\n p.commonDnfTriggers.slice(0, 3).forEach(t => {\n output += ` - ${t.trigger} (${t.count}x)\\n`;\n });\n }\n output += '\\n';\n }\n\n // Market\n if (metrics.market) {\n const m = metrics.market;\n output += `### Market Positioning\\n`;\n if (m.avgWordOfMouth) output += `- Word of Mouth Potential: ${m.avgWordOfMouth.toFixed(1)}/10\\n`;\n if (m.topComparableBooks && m.topComparableBooks.length > 0) {\n const books = m.topComparableBooks.slice(0, 3).map(b => b.title).join(', ');\n output += `- Comparable Books: ${books}\\n`;\n }\n output += '\\n';\n }\n\n return output;\n}\n\n/**\n * 格式化單一讀者反饋 (English headers for better AI processing)\n */\nfunction formatIndividualFeedback(feedback: IndividualFeedback): string {\n const name = feedback.personaName || feedback.personaToken;\n let output = `### ${name}\\n\\n`;\n\n // Overall scores\n if (feedback.overall) {\n const o = feedback.overall;\n if (o.continueReading) output += `**Continue Reading Intent**: ${o.continueReading}/10\\n`;\n if (o.recommendation) output += `**Recommendation**: ${o.recommendation}/10\\n`;\n if (o.dnfRisk) output += `**DNF Risk**: ${o.dnfRisk}\\n`;\n output += '\\n';\n }\n\n // Kindle Rating\n if (feedback.kindleRating) {\n output += `**Kindle Rating**: ⭐ ${feedback.kindleRating.score}/5`;\n if (feedback.kindleRating.rationale) {\n output += ` - ${feedback.kindleRating.rationale}`;\n }\n output += '\\n\\n';\n }\n\n // Detailed Feedback\n if (feedback.detailedFeedback) {\n const d = feedback.detailedFeedback;\n\n if (d.whatWorked) {\n output += `**What Worked**:\\n${d.whatWorked}\\n\\n`;\n }\n\n if (d.whatDidntWork) {\n output += `**What Didn't Work**:\\n${d.whatDidntWork}\\n\\n`;\n }\n\n if (d.strongestElement) {\n output += `**Strongest Element**: ${d.strongestElement}\\n`;\n }\n\n if (d.weakestElement) {\n output += `**Weakest Element**: ${d.weakestElement}\\n`;\n }\n\n if (d.wouldYouBuy) {\n output += `**Would You Buy**: ${d.wouldYouBuy}\\n`;\n }\n\n if (d.specificSuggestions && d.specificSuggestions.length > 0) {\n output += `\\n**Specific Suggestions**:\\n`;\n d.specificSuggestions.forEach((s, i) => {\n output += `${i + 1}. ${s}\\n`;\n });\n }\n\n if (d.finalThoughts) {\n output += `\\n**Final Thoughts**:\\n${d.finalThoughts}\\n`;\n }\n }\n\n // Emotional Journey\n if (feedback.emotionalJourney) {\n const e = feedback.emotionalJourney;\n if (e.emotionalArc) {\n output += `\\n**Emotional Arc**: ${e.emotionalArc}\\n`;\n }\n if (e.peakMoments && e.peakMoments.length > 0) {\n const moments = e.peakMoments.map(m =>\n typeof m === 'string' ? m : (m as { moment?: string; description?: string }).moment || (m as { moment?: string; description?: string }).description || JSON.stringify(m)\n );\n output += `**Peak Moments**: ${moments.join(', ')}\\n`;\n }\n if (e.overallMood) {\n output += `**Overall Mood**: ${e.overallMood}\\n`;\n }\n }\n\n return output;\n}\n\n/**\n * 在 snapshot 中尋找檔案(複製自 content.ts)\n */\nfunction findFileInSnapshot(\n files: FileSnapshot[],\n path: string\n): FileSnapshot | null {\n const normalizedPath = path.replace(/^\\//, '').toLowerCase();\n const pathParts = normalizedPath.split('/');\n\n function search(\n items: FileSnapshot[],\n remainingParts: string[]\n ): FileSnapshot | null {\n for (const item of items) {\n const itemNameLower = item.name.toLowerCase();\n const itemTokenLower = item.token.toLowerCase();\n\n if (remainingParts.length === 1) {\n const target = remainingParts[0];\n if (\n itemNameLower === target ||\n itemTokenLower === target ||\n itemNameLower.replace(/\\.[^.]+$/, '') === target.replace(/\\.[^.]+$/, '')\n ) {\n return item;\n }\n }\n\n if (item.kind === 'folder' && item.children) {\n if (\n itemNameLower === remainingParts[0] ||\n itemTokenLower === remainingParts[0]\n ) {\n const result = search(item.children, remainingParts.slice(1));\n if (result) return result;\n }\n\n const result = search(item.children, remainingParts);\n if (result) return result;\n }\n }\n\n return null;\n }\n\n let result = search(files, pathParts);\n if (result) return result;\n\n result = searchByName(files, pathParts[pathParts.length - 1]);\n return result;\n}\n\nfunction searchByName(\n files: FileSnapshot[],\n name: string\n): FileSnapshot | null {\n const nameLower = name.toLowerCase();\n\n for (const item of files) {\n const itemNameLower = item.name.toLowerCase();\n const itemTokenLower = item.token.toLowerCase();\n\n if (\n itemNameLower === nameLower ||\n itemTokenLower === nameLower ||\n itemNameLower.replace(/\\.[^.]+$/, '') === nameLower.replace(/\\.[^.]+$/, '')\n ) {\n return item;\n }\n\n if (item.kind === 'folder' && item.children) {\n const result = searchByName(item.children, name);\n if (result) return result;\n }\n }\n\n return null;\n}\n","/**\n * MCP File Operations Tools\n *\n * Provides tools for AI to read, write, create, delete, and search files in books.\n */\n\nimport { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { SlimaApiClient } from '../api/client.js';\nimport { formatErrorForMcp } from '../utils/errors.js';\n\n/**\n * Register file operation tools\n */\nexport function registerFileTools(\n server: McpServer,\n client: SlimaApiClient\n): void {\n // === read_file ===\n server.tool(\n 'read_file',\n 'Read the content of any file in a book by its path',\n {\n book_token: z.string().describe('Book token (e.g., bk_abc123)'),\n path: z.string().describe('File path (e.g., \"characters/protagonist.md\" or \"chapter-01.md\")'),\n },\n async ({ book_token, path }) => {\n try {\n const result = await client.readFile(book_token, path);\n\n const fileInfo = [\n `# ${result.file.name}`,\n '',\n `**Path:** ${result.file.path}`,\n `**Words:** ${result.file.wordCount}`,\n `**Type:** ${result.file.fileType || 'unknown'}`,\n '',\n '---',\n '',\n result.content || '(empty file)',\n ].join('\\n');\n\n return {\n content: [{ type: 'text', text: fileInfo }],\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: formatErrorForMcp(error) }],\n isError: true,\n };\n }\n }\n );\n\n // === write_file ===\n server.tool(\n 'write_file',\n 'Replace the entire content of an existing file (creates a new commit)',\n {\n book_token: z.string().describe('Book token (e.g., bk_abc123)'),\n path: z.string().describe('File path (e.g., \"characters/protagonist.md\")'),\n content: z.string().describe('New content to write'),\n commit_message: z.string().optional().describe('Commit message (optional, auto-generated if not provided)'),\n },\n async ({ book_token, path, content, commit_message }) => {\n try {\n const result = await client.updateFile(book_token, {\n path,\n content,\n commitMessage: commit_message,\n });\n\n return {\n content: [\n {\n type: 'text',\n text: `File updated successfully.\\n\\nCommit: ${result.commit.token}\\nMessage: ${result.commit.name || result.commit.message}`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: formatErrorForMcp(error) }],\n isError: true,\n };\n }\n }\n );\n\n // === create_file ===\n server.tool(\n 'create_file',\n 'Create a new file in a book (creates a new commit)',\n {\n book_token: z.string().describe('Book token (e.g., bk_abc123)'),\n path: z.string().describe('File path including parent folders (e.g., \"characters/new-character.md\")'),\n content: z.string().optional().describe('Initial content (optional, defaults to empty)'),\n commit_message: z.string().optional().describe('Commit message (optional, auto-generated if not provided)'),\n },\n async ({ book_token, path, content, commit_message }) => {\n try {\n const result = await client.createFile(book_token, {\n path,\n content: content || '',\n commitMessage: commit_message,\n });\n\n return {\n content: [\n {\n type: 'text',\n text: `File created successfully.\\n\\nFile Token: ${result.fileToken}\\nCommit: ${result.commit.token}\\nMessage: ${result.commit.name || result.commit.message}`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: formatErrorForMcp(error) }],\n isError: true,\n };\n }\n }\n );\n\n // === delete_file ===\n server.tool(\n 'delete_file',\n 'Delete a file from a book (creates a new commit)',\n {\n book_token: z.string().describe('Book token (e.g., bk_abc123)'),\n path: z.string().describe('File path to delete (e.g., \"old-notes.md\")'),\n commit_message: z.string().optional().describe('Commit message (optional, auto-generated if not provided)'),\n },\n async ({ book_token, path, commit_message }) => {\n try {\n const result = await client.deleteFile(book_token, {\n path,\n commitMessage: commit_message,\n });\n\n return {\n content: [\n {\n type: 'text',\n text: `File deleted successfully.\\n\\nCommit: ${result.commit.token}\\nMessage: ${result.commit.name || result.commit.message}`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: formatErrorForMcp(error) }],\n isError: true,\n };\n }\n }\n );\n\n // === append_to_file ===\n server.tool(\n 'append_to_file',\n 'Append content to the end of an existing file (creates a new commit)',\n {\n book_token: z.string().describe('Book token (e.g., bk_abc123)'),\n path: z.string().describe('File path (e.g., \"notes.md\")'),\n content: z.string().describe('Content to append'),\n commit_message: z.string().optional().describe('Commit message (optional, auto-generated if not provided)'),\n },\n async ({ book_token, path, content, commit_message }) => {\n try {\n const result = await client.appendToFile(book_token, {\n path,\n content,\n commitMessage: commit_message,\n });\n\n return {\n content: [\n {\n type: 'text',\n text: `Content appended successfully.\\n\\nCommit: ${result.commit.token}\\nMessage: ${result.commit.name || result.commit.message}`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: formatErrorForMcp(error) }],\n isError: true,\n };\n }\n }\n );\n\n // === search_content ===\n server.tool(\n 'search_content',\n 'Search for content across all files in a book',\n {\n book_token: z.string().describe('Book token (e.g., bk_abc123)'),\n query: z.string().describe('Search query (e.g., \"blue eyes\" or \"protagonist name\")'),\n file_types: z.array(z.string()).optional().describe('Filter by file types (e.g., [\"markdown\", \"txt\"])'),\n limit: z.number().optional().describe('Maximum number of matches to return (default: 20)'),\n },\n async ({ book_token, query, file_types, limit }) => {\n try {\n const result = await client.searchFiles(book_token, {\n query,\n fileTypes: file_types,\n limit,\n });\n\n if (result.matches.length === 0) {\n return {\n content: [\n {\n type: 'text',\n text: `No matches found for \"${query}\".`,\n },\n ],\n };\n }\n\n const output: string[] = [\n `# Search Results for \"${query}\"`,\n '',\n `Found ${result.matches.length} file(s) with matches:`,\n '',\n ];\n\n for (const match of result.matches) {\n output.push(`## ${match.file.path}`);\n output.push(`Words: ${match.file.wordCount} | Matches: ${match.matchCount}`);\n output.push('');\n\n for (const snippet of match.snippets) {\n output.push(`> ${snippet.text}`);\n output.push('');\n }\n }\n\n return {\n content: [{ type: 'text', text: output.join('\\n') }],\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: formatErrorForMcp(error) }],\n isError: true,\n };\n }\n }\n );\n}\n","/**\n * Token Storage Utility\n *\n * 將 API Token 儲存在使用者的 home 目錄下\n * ~/.slima/credentials.json\n */\n\nimport { promises as fs } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nconst SLIMA_DIR = '.slima';\nconst CREDENTIALS_FILE = 'credentials.json';\n\ninterface Credentials {\n apiToken: string;\n createdAt: string;\n baseUrl?: string;\n}\n\nfunction getCredentialsPath(): string {\n return join(homedir(), SLIMA_DIR, CREDENTIALS_FILE);\n}\n\nfunction getSlimaDir(): string {\n return join(homedir(), SLIMA_DIR);\n}\n\n/**\n * 儲存 API Token\n */\nexport async function saveToken(apiToken: string, baseUrl?: string): Promise<void> {\n const slimaDir = getSlimaDir();\n\n // 確保目錄存在\n await fs.mkdir(slimaDir, { recursive: true });\n\n const credentials: Credentials = {\n apiToken,\n createdAt: new Date().toISOString(),\n ...(baseUrl && { baseUrl }),\n };\n\n const credentialsPath = getCredentialsPath();\n await fs.writeFile(credentialsPath, JSON.stringify(credentials, null, 2), 'utf-8');\n\n // 設定檔案權限為 600(僅擁有者可讀寫)\n await fs.chmod(credentialsPath, 0o600);\n}\n\n/**\n * 讀取 API Token\n */\nexport async function loadToken(): Promise<Credentials | null> {\n try {\n const credentialsPath = getCredentialsPath();\n const content = await fs.readFile(credentialsPath, 'utf-8');\n return JSON.parse(content) as Credentials;\n } catch {\n return null;\n }\n}\n\n/**\n * 刪除 API Token\n */\nexport async function deleteToken(): Promise<void> {\n try {\n const credentialsPath = getCredentialsPath();\n await fs.unlink(credentialsPath);\n } catch {\n // 檔案不存在,忽略\n }\n}\n\n/**\n * 檢查是否已認證\n */\nexport async function isAuthenticated(): Promise<boolean> {\n const credentials = await loadToken();\n return credentials !== null && !!credentials.apiToken;\n}\n\n/**\n * 取得 credentials 檔案路徑(供顯示用)\n */\nexport function getCredentialsFilePath(): string {\n return getCredentialsPath();\n}\n","/**\n * CLI Auth Command\n *\n * 實作類似 Claude Code / GitHub CLI 的認證流程:\n * 1. 使用者執行 `slima-mcp auth`\n * 2. 開啟瀏覽器到 Slima 認證頁面\n * 3. 使用者登入並授權\n * 4. 本地伺服器接收 callback 並儲存 token\n */\n\nimport { createServer, type IncomingMessage, type ServerResponse } from 'node:http';\nimport { URL } from 'node:url';\nimport { randomBytes } from 'node:crypto';\nimport { saveToken, loadToken, deleteToken, getCredentialsFilePath } from '../utils/token-storage.js';\n\n// 認證使用 API 伺服器(處理 OAuth 和 session)\nconst DEFAULT_API_URL = 'https://api.slima.ai';\nconst CALLBACK_PORT_START = 8765;\nconst CALLBACK_PORT_END = 8775;\n\n/**\n * 開啟瀏覽器\n */\nasync function openBrowser(url: string): Promise<void> {\n const { exec } = await import('node:child_process');\n const { promisify } = await import('node:util');\n const execAsync = promisify(exec);\n\n const platform = process.platform;\n\n try {\n if (platform === 'darwin') {\n await execAsync(`open \"${url}\"`);\n } else if (platform === 'win32') {\n await execAsync(`start \"\" \"${url}\"`);\n } else {\n // Linux / WSL\n // 嘗試多個可能的命令\n const commands = ['xdg-open', 'sensible-browser', 'wslview'];\n for (const cmd of commands) {\n try {\n await execAsync(`${cmd} \"${url}\"`);\n return;\n } catch {\n // 繼續嘗試下一個\n }\n }\n // 如果都失敗,顯示 URL 讓使用者手動開啟\n console.log(`\\nPlease open this URL in your browser:\\n${url}\\n`);\n }\n } catch {\n console.log(`\\nPlease open this URL in your browser:\\n${url}\\n`);\n }\n}\n\n/**\n * 尋找可用的 port\n */\nasync function findAvailablePort(): Promise<number> {\n for (let port = CALLBACK_PORT_START; port <= CALLBACK_PORT_END; port++) {\n const available = await isPortAvailable(port);\n if (available) {\n return port;\n }\n }\n throw new Error(`No available ports between ${CALLBACK_PORT_START} and ${CALLBACK_PORT_END}`);\n}\n\nfunction isPortAvailable(port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const server = createServer();\n server.once('error', () => resolve(false));\n server.once('listening', () => {\n server.close(() => resolve(true));\n });\n server.listen(port, '127.0.0.1');\n });\n}\n\n/**\n * 產生隨機 state(防止 CSRF)\n */\nfunction generateState(): string {\n return randomBytes(16).toString('hex');\n}\n\n/**\n * 成功頁面 HTML\n */\nfunction getSuccessHtml(): string {\n return `<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\">\n <title>Slima MCP - Authenticated</title>\n <style>\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n display: flex;\n justify-content: center;\n align-items: center;\n height: 100vh;\n margin: 0;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n }\n .container {\n text-align: center;\n background: white;\n padding: 60px;\n border-radius: 16px;\n box-shadow: 0 20px 60px rgba(0,0,0,0.3);\n }\n .checkmark {\n font-size: 64px;\n margin-bottom: 20px;\n }\n h1 {\n color: #333;\n margin-bottom: 10px;\n }\n p {\n color: #666;\n font-size: 16px;\n }\n .hint {\n margin-top: 20px;\n color: #999;\n font-size: 14px;\n }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"checkmark\">✅</div>\n <h1>Authentication Successful!</h1>\n <p>You can now close this window and return to your terminal.</p>\n <p class=\"hint\">Slima MCP is ready to use.</p>\n </div>\n</body>\n</html>`;\n}\n\n/**\n * 錯誤頁面 HTML\n */\n/**\n * HTML escape to prevent XSS\n */\nfunction escapeHtml(text: string): string {\n const map: Record<string, string> = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#039;',\n };\n return text.replace(/[&<>\"']/g, (char) => map[char]);\n}\n\n/**\n * 錯誤頁面 HTML\n */\nfunction getErrorHtml(message: string): string {\n const safeMessage = escapeHtml(message);\n return `<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\">\n <title>Slima MCP - Error</title>\n <style>\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n display: flex;\n justify-content: center;\n align-items: center;\n height: 100vh;\n margin: 0;\n background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);\n }\n .container {\n text-align: center;\n background: white;\n padding: 60px;\n border-radius: 16px;\n box-shadow: 0 20px 60px rgba(0,0,0,0.3);\n }\n .error-icon {\n font-size: 64px;\n margin-bottom: 20px;\n }\n h1 {\n color: #e74c3c;\n margin-bottom: 10px;\n }\n p {\n color: #666;\n font-size: 16px;\n }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"error-icon\">❌</div>\n <h1>Authentication Failed</h1>\n <p>${safeMessage}</p>\n </div>\n</body>\n</html>`;\n}\n\n/**\n * 執行認證流程\n */\nexport async function runAuth(options: { baseUrl?: string } = {}): Promise<void> {\n const baseUrl = options.baseUrl || process.env.SLIMA_API_URL || DEFAULT_API_URL;\n\n console.log('\\n🔐 Slima MCP Authentication\\n');\n\n // 檢查是否已經認證\n const existingCredentials = await loadToken();\n if (existingCredentials) {\n console.log('You are already authenticated.');\n console.log(`Token stored at: ${getCredentialsFilePath()}`);\n console.log('\\nTo re-authenticate, first run: slima-mcp logout\\n');\n return;\n }\n\n const state = generateState();\n const port = await findAvailablePort();\n\n console.log('Starting local server for authentication callback...');\n\n // 建立本地伺服器接收 callback\n const tokenPromise = new Promise<string>((resolve, reject) => {\n const server = createServer((req: IncomingMessage, res: ServerResponse) => {\n const url = new URL(req.url || '/', `http://localhost:${port}`);\n\n if (url.pathname === '/callback') {\n const token = url.searchParams.get('token');\n const returnedState = url.searchParams.get('state');\n const error = url.searchParams.get('error');\n\n if (error) {\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(getErrorHtml(error));\n server.close();\n reject(new Error(error));\n return;\n }\n\n if (returnedState !== state) {\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(getErrorHtml('Invalid state parameter. Please try again.'));\n server.close();\n reject(new Error('State mismatch'));\n return;\n }\n\n if (!token) {\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(getErrorHtml('No token received. Please try again.'));\n server.close();\n reject(new Error('No token received'));\n return;\n }\n\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(getSuccessHtml());\n server.close();\n resolve(token);\n } else {\n res.writeHead(404);\n res.end('Not found');\n }\n });\n\n server.listen(port, '127.0.0.1', () => {\n console.log(`Listening on http://127.0.0.1:${port}`);\n });\n\n // 30 秒超時\n setTimeout(() => {\n server.close();\n reject(new Error('Authentication timed out. Please try again.'));\n }, 30000);\n });\n\n // 建立認證 URL(使用 API endpoint)\n const authUrl = `${baseUrl}/api/v1/auth/cli?state=${state}&callback_port=${port}`;\n\n console.log('\\nOpening browser for authentication...');\n await openBrowser(authUrl);\n\n console.log('\\nWaiting for authentication...');\n console.log('(Press Ctrl+C to cancel)\\n');\n\n try {\n const token = await tokenPromise;\n await saveToken(token, baseUrl !== DEFAULT_API_URL ? baseUrl : undefined);\n\n console.log('\\n✅ Authentication successful!');\n console.log(`Token saved to: ${getCredentialsFilePath()}`);\n console.log('\\nYou can now use Slima MCP with any MCP-compatible AI tool.\\n');\n } catch (error) {\n console.error('\\n❌ Authentication failed:', error instanceof Error ? error.message : error);\n process.exit(1);\n }\n}\n\n/**\n * 登出(刪除 token)\n */\nexport async function runLogout(): Promise<void> {\n console.log('\\n🔓 Slima MCP Logout\\n');\n\n const credentials = await loadToken();\n if (!credentials) {\n console.log('You are not authenticated.\\n');\n return;\n }\n\n await deleteToken();\n console.log('✅ Successfully logged out.');\n console.log(`Removed credentials from: ${getCredentialsFilePath()}\\n`);\n}\n\n/**\n * 顯示目前狀態\n */\nexport async function runStatus(): Promise<void> {\n console.log('\\n📊 Slima MCP Status\\n');\n\n const credentials = await loadToken();\n if (!credentials) {\n console.log('Status: Not authenticated');\n console.log('\\nRun `slima-mcp auth` to authenticate.\\n');\n return;\n }\n\n console.log('Status: Authenticated');\n console.log(`Token: ${credentials.apiToken.substring(0, 15)}...`);\n console.log(`Authenticated at: ${credentials.createdAt}`);\n if (credentials.baseUrl) {\n console.log(`API URL: ${credentials.baseUrl}`);\n }\n console.log(`Credentials file: ${getCredentialsFilePath()}\\n`);\n}\n"],"mappings":"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","names":["z","z","result","z","z","findFileInSnapshot","result","searchByName","z","z"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slima-mcp",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "MCP Server for Slima - AI Writing IDE for Novel Authors. Works with Claude, ChatGPT, Gemini, Cursor, and any MCP-compatible AI tool.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",