nworks 1.1.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/mcp.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/mcp/server.ts","../src/mcp/tools.ts","../src/utils/error.ts","../src/auth/config.ts","../src/auth/jwt.ts","../src/auth/token.ts","../src/api/client.ts","../src/api/message.ts","../src/api/directory.ts","../src/api/calendar.ts","../src/auth/oauth-user.ts","../src/auth/token-user.ts","../src/api/drive.ts","../src/api/mail.ts","../src/api/task.ts","../src/api/board.ts","../src/commands/doctor.ts","../src/output/format.ts","../src/utils/error-hints.ts","../src/output/cli-error.ts","../src/mcp.ts"],"sourcesContent":["import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { registerTools } from \"./tools.js\";\nimport { loadCredentials, loadUserToken } from \"../auth/config.js\";\n\nexport async function startMcpServer(): Promise<void> {\n // 인증 상태 확인 (경고만, 서버는 항상 시작)\n try {\n await loadCredentials();\n } catch {\n console.error(\n \"[nworks] Authentication required. Run: nworks login\"\n );\n }\n\n try {\n const userToken = await loadUserToken();\n if (!userToken) {\n console.error(\n \"[nworks] User OAuth not configured. Run: nworks login --user\"\n );\n }\n } catch {\n // ignore\n }\n\n const server = new McpServer({\n name: \"nworks\",\n version: \"1.0.0\",\n });\n\n registerTools(server);\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport * as messageApi from \"../api/message.js\";\nimport * as directoryApi from \"../api/directory.js\";\nimport * as calendarApi from \"../api/calendar.js\";\nimport * as driveApi from \"../api/drive.js\";\nimport * as mailApi from \"../api/mail.js\";\nimport * as taskApi from \"../api/task.js\";\nimport * as boardApi from \"../api/board.js\";\nimport { clearCredentials, loadCredentials, loadToken, loadUserToken, saveCredentials, saveUserToken } from \"../auth/config.js\";\nimport { runChecks } from \"../commands/doctor.js\";\nimport { buildAuthorizeUrl, startOAuthCallbackServer } from \"../auth/oauth-user.js\";\nimport { mcpErrorHint } from \"../utils/error-hints.js\";\n\nexport function registerTools(server: McpServer): void {\n // Tool 0: 초기 설정\n server.tool(\n \"nworks_setup\",\n \"NAVER WORKS API 인증 정보를 설정합니다. clientId는 필수, clientSecret은 환경변수(NWORKS_CLIENT_SECRET)로도 설정 가능합니다. 민감 정보는 환경변수로 설정하는 것을 권장합니다 (NWORKS_CLIENT_ID, NWORKS_CLIENT_SECRET 등). 메시지/구성원조회는 Service Account 인증(serviceAccount, privateKeyPath, botId 추가 필요). 캘린더/메일/할일/드라이브/게시판은 User OAuth 인증(설정 후 nworks_login_user로 브라우저 로그인 필요). OAuth Redirect URI: http://localhost:9876/callback\",\n {\n clientId: z.string().describe(\"Client ID (Developer Console에서 발급)\"),\n clientSecret: z.string().optional().describe(\"Client Secret (Developer Console에서 발급). 환경변수 NWORKS_CLIENT_SECRET이 설정되어 있으면 생략 가능\"),\n serviceAccount: z.string().optional().describe(\"Service Account ID (예: xxxxx.serviceaccount@domain)\"),\n privateKeyPath: z.string().optional().describe(\"Private Key 파일의 로컬 절대 경로 (서비스 계정 인증 시 필요). 사용자에게 파일이 저장된 경로를 직접 물어보세요 (예: C:\\\\Users\\\\me\\\\Downloads\\\\private.key). 파일 업로드가 아닌 경로 문자열입니다.\"),\n botId: z.string().optional().describe(\"Bot ID (메시지 전송 시 필요)\"),\n domainId: z.string().optional().describe(\"Domain ID\"),\n },\n async ({ clientId, clientSecret, serviceAccount, privateKeyPath, botId, domainId }) => {\n try {\n // clientSecret: 파라미터 → 환경변수 순으로 확인\n const resolvedSecret = clientSecret || process.env[\"NWORKS_CLIENT_SECRET\"];\n if (!resolvedSecret) {\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify({ error: true, message: \"clientSecret이 필요합니다. 파라미터로 전달하거나 환경변수 NWORKS_CLIENT_SECRET을 설정하세요.\" }) }],\n isError: true,\n };\n }\n\n await saveCredentials({\n clientId,\n clientSecret: resolvedSecret,\n serviceAccount,\n privateKeyPath,\n botId,\n domainId,\n });\n\n const nextSteps: string[] = [];\n if (serviceAccount && privateKeyPath && botId) {\n nextSteps.push(\"Service Account 인증 준비 완료 — 봇 메시지 등 바로 사용 가능\");\n }\n nextSteps.push(\"User OAuth가 필요한 API는 nworks_login_user tool로 브라우저 로그인을 진행하세요\");\n\n const mask = (s: string) => s.length <= 4 ? \"****\" : `****${s.slice(-Math.min(4, Math.floor(s.length / 3)))}`;\n const secretSource = clientSecret ? \"파라미터\" : \"환경변수\";\n\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({\n success: true,\n message: \"인증 정보가 저장되었습니다.\",\n nextSteps,\n clientId,\n clientSecret: `${mask(resolvedSecret)} (${secretSource})`,\n serviceAccount: serviceAccount ?? null,\n privateKeyPath: privateKeyPath ? mask(privateKeyPath) : null,\n botId: botId ?? null,\n }),\n },\n ],\n };\n } catch (err) {\n return {\n content: [{ type: \"text\" as const, text: mcpErrorHint(err) }],\n isError: true,\n };\n }\n }\n );\n\n // Tool 1: 메시지 전송\n server.tool(\n \"nworks_message_send\",\n \"NAVER WORKS 메시지를 전송합니다 (봇이 사용자 또는 채널에 발송). Service Account 인증 사용 (nworks_setup에서 serviceAccount, privateKeyPath, botId 설정 필요. User OAuth 불필요)\",\n {\n to: z.string().optional().describe(\"수신자 userId (channel과 택 1). nworks_directory_members로 userId 조회 가능\"),\n channel: z.string().optional().describe(\"채널 channelId (to와 택 1). nworks_message_members로 채널 구성원 확인 가능\"),\n text: z.string().describe(\"메시지 본문\"),\n type: z\n .enum([\"text\", \"button\", \"list\"])\n .optional()\n .describe(\"메시지 타입 (기본: text)\"),\n actions: z\n .string()\n .optional()\n .describe(\"버튼 액션 JSON (type=button일 때)\"),\n elements: z\n .string()\n .optional()\n .describe(\"리스트 항목 JSON (type=list일 때)\"),\n },\n async ({ to, channel, text, type, actions, elements }) => {\n try {\n const result = await messageApi.send({\n to,\n channel,\n text,\n type,\n actions,\n elements,\n });\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(result) }],\n };\n } catch (err) {\n return {\n content: [{ type: \"text\" as const, text: mcpErrorHint(err) }],\n isError: true,\n };\n }\n }\n );\n\n // Tool 2: 채널 구성원\n server.tool(\n \"nworks_message_members\",\n \"특정 채널의 구성원 목록을 조회합니다. '이 채널에 누가 있어?' 등의 요청에 사용. Service Account 인증 사용 (nworks_setup 필요)\",\n {\n channel: z.string().describe(\"채널 channelId\"),\n },\n async ({ channel }) => {\n try {\n const result = await messageApi.listMembers(channel);\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(result) }],\n };\n } catch (err) {\n return {\n content: [{ type: \"text\" as const, text: mcpErrorHint(err) }],\n isError: true,\n };\n }\n }\n );\n\n // Tool 3: 조직 구성원 목록\n server.tool(\n \"nworks_directory_members\",\n \"NAVER WORKS 조직 구성원(직원) 목록을 조회합니다. '구성원 목록 보여줘', '팀원 찾아줘', '누구한테 메시지 보낼지 userId 찾기' 등에 사용. Service Account 인증 사용 (nworks_setup 필요). 메시지 전송 시 수신자 userId를 여기서 조회 가능\",\n {},\n async () => {\n try {\n const result = await directoryApi.listUsers();\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(result) }],\n };\n } catch (err) {\n return {\n content: [{ type: \"text\" as const, text: mcpErrorHint(err) }],\n isError: true,\n };\n }\n }\n );\n\n // Tool 4: 캘린더 일정 목록\n server.tool(\n \"nworks_calendar_list\",\n \"사용자의 캘린더 일정/스케줄을 조회합니다. '오늘 일정 알려줘', '이번 주 스케줄 확인' 등의 요청에 사용. User OAuth 인증 필요 (calendar.read scope). 미로그인 시 nworks_login_user로 로그인 필요\",\n {\n fromDateTime: z.string().describe(\"시작 일시 (YYYY-MM-DDThh:mm:ss+09:00)\"),\n untilDateTime: z.string().describe(\"종료 일시 (YYYY-MM-DDThh:mm:ss+09:00)\"),\n userId: z.string().optional().describe(\"대상 사용자 ID (미지정 시 me)\"),\n },\n async ({ fromDateTime, untilDateTime, userId }) => {\n try {\n const result = await calendarApi.listEvents(\n fromDateTime,\n untilDateTime,\n userId ?? \"me\"\n );\n const events = result.events.flatMap((e) =>\n e.eventComponents.map((c) => ({\n eventId: c.eventId,\n summary: c.summary,\n start: c.start.dateTime ?? c.start.date ?? \"\",\n end: c.end.dateTime ?? c.end.date ?? \"\",\n location: c.location ?? \"\",\n }))\n );\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify({ events, count: events.length }) }],\n };\n } catch (err) {\n return {\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"calendar.list\") }],\n isError: true,\n };\n }\n }\n );\n\n // Tool 5: 캘린더 일정 생성\n server.tool(\n \"nworks_calendar_create\",\n \"캘린더 일정을 새로 만듭니다. '회의 잡아줘', '일정 등록해줘' 등의 요청에 사용. User OAuth 인증 필요 (calendar + calendar.read scope)\",\n {\n summary: z.string().describe(\"일정 제목\"),\n start: z.string().describe(\"시작 일시 (YYYY-MM-DDThh:mm:ss)\"),\n end: z.string().describe(\"종료 일시 (YYYY-MM-DDThh:mm:ss)\"),\n timeZone: z.string().optional().describe(\"타임존 (기본: Asia/Seoul)\"),\n description: z.string().optional().describe(\"일정 설명\"),\n location: z.string().optional().describe(\"장소\"),\n attendees: z.array(z.object({ email: z.string(), displayName: z.string().optional() })).optional().describe(\"참석자 목록\"),\n sendNotification: z.boolean().optional().describe(\"참석자에게 알림 발송 (기본: false)\"),\n userId: z.string().optional().describe(\"대상 사용자 ID (미지정 시 me)\"),\n },\n async ({ summary, start, end, timeZone, description, location, attendees, sendNotification, userId }) => {\n try {\n const result = await calendarApi.createEvent({\n summary,\n start,\n end,\n timeZone,\n description,\n location,\n attendees,\n sendNotification,\n userId: userId ?? \"me\",\n });\n const event = result.eventComponents?.[0];\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify({ success: true, eventId: event?.eventId, summary: event?.summary, start: event?.start, end: event?.end }) }],\n };\n } catch (err) {\n return {\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"calendar.create\") }],\n isError: true,\n };\n }\n }\n );\n\n // Tool 6: 캘린더 일정 수정\n server.tool(\n \"nworks_calendar_update\",\n \"기존 캘린더 일정을 수정합니다. '일정 시간 변경해줘', '회의 제목 바꿔줘' 등의 요청에 사용. User OAuth 인증 필요 (calendar + calendar.read scope). eventId는 nworks_calendar_list로 조회 가능\",\n {\n eventId: z.string().describe(\"일정 ID (nworks_calendar_list로 조회 가능)\"),\n summary: z.string().optional().describe(\"새 제목\"),\n start: z.string().optional().describe(\"새 시작 일시 (YYYY-MM-DDThh:mm:ss)\"),\n end: z.string().optional().describe(\"새 종료 일시 (YYYY-MM-DDThh:mm:ss)\"),\n timeZone: z.string().optional().describe(\"타임존 (기본: Asia/Seoul)\"),\n description: z.string().optional().describe(\"새 설명\"),\n location: z.string().optional().describe(\"새 장소\"),\n sendNotification: z.boolean().optional().describe(\"참석자에게 알림 발송 (기본: false)\"),\n userId: z.string().optional().describe(\"대상 사용자 ID (미지정 시 me)\"),\n },\n async ({ eventId, summary, start, end, timeZone, description, location, sendNotification, userId }) => {\n try {\n await calendarApi.updateEvent({\n eventId,\n summary,\n start,\n end,\n timeZone,\n description,\n location,\n sendNotification,\n userId: userId ?? \"me\",\n });\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify({ success: true, eventId, message: \"일정이 수정되었습니다\" }) }],\n };\n } catch (err) {\n return {\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"calendar.update\") }],\n isError: true,\n };\n }\n }\n );\n\n // Tool 7: 캘린더 일정 삭제\n server.tool(\n \"nworks_calendar_delete\",\n \"캘린더 일정을 삭제합니다. '일정 취소해줘' 등의 요청에 사용. User OAuth 인증 필요 (calendar + calendar.read scope). eventId는 nworks_calendar_list로 조회 가능\",\n {\n eventId: z.string().describe(\"삭제할 일정 ID (nworks_calendar_list로 조회 가능)\"),\n sendNotification: z.boolean().optional().describe(\"참석자에게 알림 발송 (기본: false)\"),\n userId: z.string().optional().describe(\"대상 사용자 ID (미지정 시 me)\"),\n },\n async ({ eventId, sendNotification, userId }) => {\n try {\n await calendarApi.deleteEvent(\n eventId,\n userId ?? \"me\",\n sendNotification ?? false\n );\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify({ success: true, eventId, message: \"일정이 삭제되었습니다\" }) }],\n };\n } catch (err) {\n return {\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"calendar.delete\") }],\n isError: true,\n };\n }\n }\n );\n\n // Tool 8: 드라이브 파일 목록\n server.tool(\n \"nworks_drive_list\",\n \"NAVER WORKS 드라이브의 파일/폴더 목록을 조회합니다. '드라이브 파일 보여줘', '내 파일 목록' 등의 요청에 사용. User OAuth 인증 필요 (file.read scope)\",\n {\n userId: z.string().optional().describe(\"대상 사용자 ID (미지정 시 me)\"),\n folderId: z.string().optional().describe(\"폴더 ID (미지정 시 루트)\"),\n count: z.number().optional().describe(\"페이지당 항목 수 (기본: 20, 최대: 200)\"),\n cursor: z.string().optional().describe(\"페이지네이션 커서\"),\n },\n async ({ userId, folderId, count, cursor }) => {\n try {\n const result = await driveApi.listFiles(\n userId ?? \"me\",\n folderId,\n count ?? 20,\n cursor\n );\n const files = result.files.map((f) => ({\n fileId: f.fileId,\n name: f.fileName,\n type: f.fileType,\n size: f.fileSize,\n modified: f.modifiedTime,\n path: f.filePath,\n }));\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify({ files, count: files.length, hasMore: !!result.responseMetaData?.nextCursor, nextCursor: result.responseMetaData?.nextCursor ?? null }) }],\n };\n } catch (err) {\n return {\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"drive.list\") }],\n isError: true,\n };\n }\n }\n );\n\n // Tool 9: 드라이브 파일 업로드\n server.tool(\n \"nworks_drive_upload\",\n \"파일을 드라이브에 업로드합니다 (User OAuth file scope 필요). content(base64)와 fileName으로 전달하거나, filePath로 로컬 파일 경로를 지정합니다. MCP 클라이언트에서는 content+fileName 방식을 권장합니다.\",\n {\n content: z.string().optional().describe(\"업로드할 파일 내용 (base64 인코딩). filePath 대신 사용\"),\n fileName: z.string().optional().describe(\"파일명 (content 사용 시 필수)\"),\n filePath: z.string().optional().describe(\"업로드할 로컬 파일 경로 (content 대신 사용, 로컬 환경에서만 동작)\"),\n userId: z.string().optional().describe(\"대상 사용자 ID (미지정 시 me)\"),\n folderId: z.string().optional().describe(\"업로드할 폴더 ID (미지정 시 루트)\"),\n overwrite: z.boolean().optional().describe(\"동일 파일명 덮어쓰기 (기본: false)\"),\n },\n async ({ content, fileName, filePath, userId, folderId, overwrite }) => {\n try {\n let result: driveApi.UploadResult;\n\n if (content && fileName) {\n // MCP 방식: base64 content를 직접 받아서 업로드\n const buffer = Buffer.from(content, \"base64\");\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] MCP upload: fileName=${fileName}, bufferSize=${buffer.length}`);\n }\n result = await driveApi.uploadBuffer(\n buffer,\n fileName,\n userId ?? \"me\",\n folderId,\n overwrite ?? false\n );\n } else if (filePath) {\n // 로컬 파일 경로 방식\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] MCP upload: filePath=${filePath}`);\n }\n result = await driveApi.uploadFile(\n filePath,\n userId ?? \"me\",\n folderId,\n overwrite ?? false\n );\n } else {\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify({ error: true, message: \"content+fileName 또는 filePath 중 하나를 지정해야 합니다. MCP 클라이언트에서는 파일 내용을 base64로 인코딩하여 content 파라미터에 전달하고, fileName에 파일명을 지정하세요.\" }) }],\n isError: true,\n };\n }\n\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify({ success: true, ...result }) }],\n };\n } catch (err) {\n const error = err as Error;\n const detail = process.env[\"NWORKS_VERBOSE\"] === \"1\"\n ? ` | stack: ${error.stack}`\n : \"\";\n return {\n content: [{ type: \"text\" as const, text: `${mcpErrorHint(err, \"drive.upload\")}${detail}` }],\n isError: true,\n };\n }\n }\n );\n\n // Tool 10: 드라이브 파일 다운로드\n server.tool(\n \"nworks_drive_download\",\n \"드라이브 파일을 다운로드합니다. User OAuth 인증 필요 (file.read scope). outputDir을 지정하면 로컬에 파일로 저장하고, 미지정 시 파일 내용을 직접 반환합니다 (텍스트는 text, 바이너리는 base64). 5MB 초과 파일은 반드시 outputDir를 지정해야 합니다.\",\n {\n fileId: z.string().describe(\"다운로드할 파일 ID (nworks_drive_list로 조회 가능)\"),\n outputDir: z.string().optional().describe(\"저장 디렉토리 (지정 시 파일로 저장, 미지정 시 내용을 직접 반환)\"),\n outputName: z.string().optional().describe(\"저장 파일명 (미지정 시 원본 파일명)\"),\n userId: z.string().optional().describe(\"대상 사용자 ID (미지정 시 me)\"),\n },\n async ({ fileId, outputDir, outputName, userId }) => {\n try {\n const result = await driveApi.downloadFile(\n fileId,\n userId ?? \"me\"\n );\n\n const fileName = outputName ?? result.fileName ?? fileId;\n\n if (outputDir) {\n // 로컬 저장 방식 (CLI 환경용)\n const { writeFile } = await import(\"node:fs/promises\");\n const { join } = await import(\"node:path\");\n const outPath = join(outputDir, fileName);\n await writeFile(outPath, result.buffer);\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify({ success: true, fileName, path: outPath, size: result.buffer.length }) }],\n };\n }\n\n // 내용 직접 반환 방식 (MCP 환경용)\n const MAX_INLINE_SIZE = 5 * 1024 * 1024; // 5MB\n if (result.buffer.length > MAX_INLINE_SIZE) {\n const sizeMB = (result.buffer.length / (1024 * 1024)).toFixed(1);\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify({ error: true, message: `파일이 너무 큽니다 (${sizeMB}MB). outputDir를 지정해서 로컬에 저장하세요.`, fileName, size: result.buffer.length }) }],\n isError: true,\n };\n }\n\n const textExtensions = /\\.(txt|md|csv|json|xml|html|htm|css|js|ts|jsx|tsx|yaml|yml|toml|ini|cfg|conf|log|sh|bash|zsh|py|rb|java|go|rs|c|cpp|h|hpp|sql|graphql|env|gitignore|dockerignore|editorconfig)$/i;\n const isText = textExtensions.test(fileName);\n\n if (isText) {\n const text = result.buffer.toString(\"utf-8\");\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify({ success: true, fileName, size: result.buffer.length, encoding: \"text\", content: text }) }],\n };\n }\n\n const base64 = result.buffer.toString(\"base64\");\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify({ success: true, fileName, size: result.buffer.length, encoding: \"base64\", content: base64 }) }],\n };\n } catch (err) {\n return {\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"drive.download\") }],\n isError: true,\n };\n }\n }\n );\n\n // Tool 11: 메일 전송\n server.tool(\n \"nworks_mail_send\",\n \"NAVER WORKS 메일을 전송합니다. '메일 보내줘', '이메일 작성해줘' 등의 요청에 사용. 비동기 전송(성공 시 202). User OAuth 인증 필요 (mail scope)\",\n {\n to: z.string().describe(\"수신자 이메일 (여러 명은 ; 로 구분)\"),\n subject: z.string().describe(\"메일 제목\"),\n body: z.string().optional().describe(\"메일 본문\"),\n cc: z.string().optional().describe(\"참조 이메일 (여러 명은 ; 로 구분)\"),\n bcc: z.string().optional().describe(\"숨은참조 이메일 (여러 명은 ; 로 구분)\"),\n contentType: z.enum([\"html\", \"text\"]).optional().describe(\"본문 형식 (기본: html)\"),\n userId: z.string().optional().describe(\"발신자 ID (미지정 시 me)\"),\n },\n async ({ to, subject, body, cc, bcc, contentType, userId }) => {\n try {\n await mailApi.sendMail({\n to,\n subject,\n body,\n cc,\n bcc,\n contentType,\n userId: userId ?? \"me\",\n });\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify({ success: true, message: \"메일이 전송되었습니다 (비동기 처리)\" }) }],\n };\n } catch (err) {\n return {\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"mail.send\") }],\n isError: true,\n };\n }\n }\n );\n\n // Tool 12: 메일 목록 조회\n server.tool(\n \"nworks_mail_list\",\n \"받은 메일 목록을 조회합니다. '메일 확인해줘', '받은편지함 보여줘', '안 읽은 메일 있어?' 등의 요청에 사용. User OAuth 인증 필요 (mail.read scope)\",\n {\n folderId: z.number().optional().describe(\"메일 폴더 ID (기본: 0 = 받은편지함)\"),\n count: z.number().optional().describe(\"페이지당 항목 수 (기본: 30, 최대: 200)\"),\n cursor: z.string().optional().describe(\"페이지네이션 커서\"),\n isUnread: z.boolean().optional().describe(\"읽지 않은 메일만 조회\"),\n userId: z.string().optional().describe(\"대상 사용자 ID (미지정 시 me)\"),\n },\n async ({ folderId, count, cursor, isUnread, userId }) => {\n try {\n const result = await mailApi.listMails(\n folderId ?? 0,\n userId ?? \"me\",\n count ?? 30,\n cursor,\n isUnread\n );\n const mails = result.mails.map((m) => ({\n mailId: m.mailId,\n from: m.from.email,\n subject: m.subject,\n date: m.receivedTime,\n status: m.status,\n attachments: m.attachCount ?? 0,\n }));\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify({ mails, count: mails.length, totalCount: result.totalCount, unreadCount: result.unreadCount, hasMore: !!result.responseMetaData?.nextCursor, nextCursor: result.responseMetaData?.nextCursor ?? null }) }],\n };\n } catch (err) {\n return {\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"mail.list\") }],\n isError: true,\n };\n }\n }\n );\n\n // Tool 13: 메일 상세 조회\n server.tool(\n \"nworks_mail_read\",\n \"특정 메일의 상세 내용(본문, 첨부파일 등)을 조회합니다. '이 메일 내용 보여줘' 등의 요청에 사용. mailId는 nworks_mail_list로 조회 가능. User OAuth 인증 필요 (mail.read scope)\",\n {\n mailId: z.number().describe(\"메일 ID (nworks_mail_list로 조회 가능)\"),\n userId: z.string().optional().describe(\"대상 사용자 ID (미지정 시 me)\"),\n },\n async ({ mailId, userId }) => {\n try {\n const result = await mailApi.readMail(\n mailId,\n userId ?? \"me\"\n );\n const mail = result.mail;\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify({\n mailId: mail.mailId,\n from: mail.from,\n to: mail.to,\n cc: mail.cc ?? [],\n subject: mail.subject,\n body: mail.body,\n date: mail.receivedTime,\n attachments: result.attachments?.map((a) => ({\n id: a.attachmentId,\n filename: a.filename,\n contentType: a.contentType,\n size: a.size,\n })) ?? [],\n }) }],\n };\n } catch (err) {\n return {\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"mail.read\") }],\n isError: true,\n };\n }\n }\n );\n\n // Tool 14: 할 일 목록 조회\n server.tool(\n \"nworks_task_list\",\n \"할 일(TODO) 목록을 조회합니다. '할 일 확인해줘', 'TODO 목록 보여줘', '남은 업무 뭐 있어?' 등의 요청에 사용. User OAuth 인증 필요 (task.read scope)\",\n {\n categoryId: z.string().optional().describe(\"카테고리 ID (기본: default)\"),\n status: z.enum([\"TODO\", \"ALL\"]).optional().describe(\"필터: TODO 또는 ALL (기본: ALL)\"),\n count: z.number().optional().describe(\"페이지당 항목 수 (기본: 50, 최대: 100)\"),\n cursor: z.string().optional().describe(\"페이지네이션 커서\"),\n userId: z.string().optional().describe(\"대상 사용자 ID (미지정 시 me)\"),\n },\n async ({ categoryId, status, count, cursor, userId }) => {\n try {\n const result = await taskApi.listTasks(\n categoryId ?? \"default\",\n userId ?? \"me\",\n count ?? 50,\n cursor,\n status ?? \"ALL\"\n );\n const tasks = result.tasks.map((t) => ({\n taskId: t.taskId,\n title: t.title,\n status: t.status,\n dueDate: t.dueDate,\n assignor: t.assignorName ?? t.assignorId,\n created: t.createdTime,\n }));\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify({ tasks, count: tasks.length, hasMore: !!result.responseMetaData?.nextCursor, nextCursor: result.responseMetaData?.nextCursor ?? null }) }],\n };\n } catch (err) {\n return {\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"task.list\") }],\n isError: true,\n };\n }\n }\n );\n\n // Tool 15: 할 일 생성\n server.tool(\n \"nworks_task_create\",\n \"할 일(TODO)을 새로 만듭니다. '할 일 추가해줘', 'TODO 등록해줘' 등의 요청에 사용. 기본적으로 자기 자신에게 할당. User OAuth 인증 필요 (task + user.read scope)\",\n {\n title: z.string().describe(\"할 일 제목\"),\n content: z.string().optional().describe(\"할 일 내용\"),\n dueDate: z.string().optional().describe(\"마감일 (YYYY-MM-DD)\"),\n categoryId: z.string().optional().describe(\"카테고리 ID\"),\n assigneeIds: z.array(z.string()).optional().describe(\"담당자 user ID 목록 (미지정 시 자기 자신)\"),\n userId: z.string().optional().describe(\"생성자 user ID (미지정 시 me)\"),\n },\n async ({ title, content, dueDate, categoryId, assigneeIds, userId }) => {\n try {\n const result = await taskApi.createTask({\n title,\n content,\n dueDate,\n categoryId,\n assigneeIds,\n userId: userId ?? \"me\",\n });\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify({ success: true, taskId: result.taskId, title: result.title, status: result.status, dueDate: result.dueDate }) }],\n };\n } catch (err) {\n return {\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"task.create\") }],\n isError: true,\n };\n }\n }\n );\n\n // Tool 16: 할 일 수정\n server.tool(\n \"nworks_task_update\",\n \"할 일을 수정하거나 완료 처리합니다. '할 일 완료 처리해줘', '마감일 변경해줘' 등의 요청에 사용. taskId는 nworks_task_list로 조회 가능. User OAuth 인증 필요 (task + user.read scope)\",\n {\n taskId: z.string().describe(\"할 일 ID (nworks_task_list로 조회 가능)\"),\n status: z.enum([\"done\", \"todo\"]).optional().describe(\"상태 변경: done(완료) 또는 todo(미완료)\"),\n title: z.string().optional().describe(\"새 제목\"),\n content: z.string().optional().describe(\"새 내용\"),\n dueDate: z.string().optional().describe(\"새 마감일 (YYYY-MM-DD)\"),\n },\n async ({ taskId, status, title, content, dueDate }) => {\n try {\n // 상태 변경\n if (status) {\n if (status === \"done\") {\n await taskApi.completeTask(taskId);\n } else {\n await taskApi.incompleteTask(taskId);\n }\n }\n\n // 필드 수정\n if (title !== undefined || content !== undefined || dueDate !== undefined) {\n const result = await taskApi.updateTask({ taskId, title, content, dueDate });\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify({ success: true, taskId: result.taskId, title: result.title, status: result.status, dueDate: result.dueDate }) }],\n };\n }\n\n if (status) {\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify({ success: true, taskId, status: status === \"done\" ? \"DONE\" : \"TODO\" }) }],\n };\n }\n\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify({ error: true, message: \"status, title, content, dueDate 중 하나 이상을 지정하세요.\" }) }],\n isError: true,\n };\n } catch (err) {\n return {\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"task.update\") }],\n isError: true,\n };\n }\n }\n );\n\n // Tool 17: 할 일 삭제\n server.tool(\n \"nworks_task_delete\",\n \"할 일을 삭제합니다. taskId는 nworks_task_list로 조회 가능. User OAuth 인증 필요 (task + user.read scope)\",\n {\n taskId: z.string().describe(\"삭제할 할 일 ID (nworks_task_list로 조회 가능)\"),\n },\n async ({ taskId }) => {\n try {\n await taskApi.deleteTask(taskId);\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify({ success: true, taskId, message: \"할 일이 삭제되었습니다\" }) }],\n };\n } catch (err) {\n return {\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"task.delete\") }],\n isError: true,\n };\n }\n }\n );\n\n // Tool 18: 게시판 목록\n server.tool(\n \"nworks_board_list\",\n \"NAVER WORKS 게시판 목록을 조회합니다. '게시판 뭐 있어?', '공지사항 게시판 찾아줘' 등의 요청에 사용. User OAuth 인증 필요 (board.read scope)\",\n {\n count: z.number().optional().describe(\"페이지당 항목 수 (기본: 20)\"),\n cursor: z.string().optional().describe(\"페이지네이션 커서\"),\n },\n async ({ count, cursor }) => {\n try {\n const result = await boardApi.listBoards(count ?? 20, cursor);\n const boards = result.boards.map((b) => ({\n boardId: b.boardId,\n boardName: b.boardName,\n description: b.description ?? \"\",\n }));\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify({ boards, count: boards.length, hasMore: !!result.responseMetaData?.nextCursor, nextCursor: result.responseMetaData?.nextCursor ?? null }) }],\n };\n } catch (err) {\n return {\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"board.list\") }],\n isError: true,\n };\n }\n }\n );\n\n // Tool 19: 게시판 글 목록\n server.tool(\n \"nworks_board_posts\",\n \"게시판의 글 목록을 조회합니다. '게시판 글 보여줘', '공지사항 확인' 등의 요청에 사용. boardId는 nworks_board_list로 조회 가능. User OAuth 인증 필요 (board.read scope)\",\n {\n boardId: z.string().describe(\"게시판 ID (nworks_board_list로 조회 가능)\"),\n count: z.number().optional().describe(\"페이지당 항목 수 (기본: 20, 최대: 40)\"),\n cursor: z.string().optional().describe(\"페이지네이션 커서\"),\n },\n async ({ boardId, count, cursor }) => {\n try {\n const result = await boardApi.listPosts(boardId, count ?? 20, cursor);\n const posts = result.posts.map((p) => ({\n postId: p.postId,\n title: p.title,\n userName: p.userName ?? \"\",\n readCount: p.readCount ?? 0,\n commentCount: p.commentCount ?? 0,\n createdTime: p.createdTime ?? \"\",\n }));\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify({ posts, count: posts.length, hasMore: !!result.responseMetaData?.nextCursor, nextCursor: result.responseMetaData?.nextCursor ?? null }) }],\n };\n } catch (err) {\n return {\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"board.posts\") }],\n isError: true,\n };\n }\n }\n );\n\n // Tool 20: 게시판 글 상세 조회\n server.tool(\n \"nworks_board_read\",\n \"게시판 글의 상세 내용을 조회합니다. postId는 nworks_board_posts로 조회 가능. User OAuth 인증 필요 (board.read scope)\",\n {\n boardId: z.string().describe(\"게시판 ID (nworks_board_list로 조회 가능)\"),\n postId: z.string().describe(\"글 ID (nworks_board_posts로 조회 가능)\"),\n },\n async ({ boardId, postId }) => {\n try {\n const post = await boardApi.readPost(boardId, postId);\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify({\n postId: post.postId,\n boardId: post.boardId,\n title: post.title,\n body: post.body ?? \"\",\n userName: post.userName ?? \"\",\n readCount: post.readCount ?? 0,\n commentCount: post.commentCount ?? 0,\n createdTime: post.createdTime ?? \"\",\n updatedTime: post.updatedTime ?? \"\",\n }) }],\n };\n } catch (err) {\n return {\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"board.read\") }],\n isError: true,\n };\n }\n }\n );\n\n // Tool 21: 게시판 글 작성\n server.tool(\n \"nworks_board_create\",\n \"게시판에 글을 작성합니다. '게시판에 글 올려줘', '공지 작성해줘' 등의 요청에 사용. boardId는 nworks_board_list로 조회 가능. User OAuth 인증 필요 (board scope)\",\n {\n boardId: z.string().describe(\"게시판 ID (nworks_board_list로 조회 가능)\"),\n title: z.string().describe(\"글 제목\"),\n body: z.string().optional().describe(\"글 본문\"),\n enableComment: z.boolean().optional().describe(\"댓글 허용 (기본: true)\"),\n sendNotifications: z.boolean().optional().describe(\"알림 발송 (기본: false)\"),\n },\n async ({ boardId, title, body, enableComment, sendNotifications }) => {\n try {\n const post = await boardApi.createPost({\n boardId,\n title,\n body,\n enableComment,\n sendNotifications,\n });\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify({ success: true, postId: post.postId, boardId: post.boardId, title: post.title }) }],\n };\n } catch (err) {\n return {\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"board.create\") }],\n isError: true,\n };\n }\n }\n );\n\n // Tool 22: User OAuth 로그인\n server.tool(\n \"nworks_login_user\",\n \"User OAuth 로그인을 시작합니다. 반환된 URL을 브라우저에서 열어 NAVER WORKS에 로그인하세요. 로그인 완료 후 자동으로 토큰이 저장됩니다. 중요: scope를 지정하지 마세요. 기본값이 모든 API(캘린더, 메일, 할일, 드라이브, 게시판)를 포함하므로 한 번 로그인으로 전체 기능을 사용할 수 있습니다. scope를 좁게 지정하면 다른 기능 사용 시 재로그인이 필요합니다.\",\n {\n scope: z\n .string()\n .optional()\n .describe(\"지정하지 마세요 (기본값이 전체 scope 포함). 특수한 경우에만 사용\"),\n },\n async ({ scope }) => {\n const DEFAULT_SCOPE = \"calendar calendar.read file file.read mail mail.read task task.read user.read board board.read\";\n try {\n const creds = await loadCredentials();\n\n // scope 의존성 자동 확장\n // - calendar 쓰기는 calendar.read 필요 (수정/삭제 시 기존 일정 조회)\n // - task 쓰기는 user.read 필요 (/users/me 호출)\n const SCOPE_DEPS: Record<string, string[]> = {\n calendar: [\"calendar.read\"],\n task: [\"user.read\"],\n \"task.read\": [\"user.read\"],\n };\n\n const expandScopes = (scopes: string[]): string[] => {\n const expanded = new Set(scopes);\n for (const s of scopes) {\n const deps = SCOPE_DEPS[s];\n if (deps) deps.forEach((d) => expanded.add(d));\n }\n return [...expanded];\n };\n\n // 기존 토큰의 scope와 합치기\n const existingToken = await loadUserToken();\n const existingScopes = existingToken?.scope?.split(\" \").filter(Boolean) ?? [];\n const requestedScopes = expandScopes((scope ?? DEFAULT_SCOPE).split(\" \").filter(Boolean));\n const mergedScopes = [...new Set([...existingScopes, ...requestedScopes])].join(\" \");\n\n const state = Math.random().toString(36).substring(2);\n const authorizeUrl = buildAuthorizeUrl(creds.clientId, mergedScopes, state);\n\n // 콜백 서버를 백그라운드로 시작 (토큰 교환 및 저장까지 자동 처리)\n startOAuthCallbackServer(creds.clientId, creds.clientSecret)\n .then((token) =>\n saveUserToken({\n accessToken: token.accessToken,\n refreshToken: token.refreshToken,\n expiresAt: token.expiresAt,\n scope: token.scope,\n })\n )\n .then(() => {\n console.error(\"[nworks] User OAuth login successful. Token saved.\");\n })\n .catch((err: Error) => {\n console.error(`[nworks] User OAuth login failed: ${err.message}`);\n });\n\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({\n message:\n \"아래 URL을 브라우저에서 열어 NAVER WORKS에 로그인하세요. 로그인 완료 후 자동으로 토큰이 저장됩니다. (제한시간: 120초)\",\n loginUrl: authorizeUrl,\n scope: mergedScopes,\n callbackPort: 9876,\n timeout: \"120초\",\n }),\n },\n ],\n };\n } catch (err) {\n return {\n content: [{ type: \"text\" as const, text: mcpErrorHint(err) }],\n isError: true,\n };\n }\n }\n );\n\n // Tool 23: 인증 상태\n server.tool(\n \"nworks_whoami\",\n \"현재 인증된 NAVER WORKS 계정 정보와 토큰 유효 상태를 확인합니다. 인증 문제 진단 시 먼저 호출\",\n {},\n async () => {\n try {\n const creds = await loadCredentials();\n const token = await loadToken();\n const userToken = await loadUserToken();\n const isValid = token\n ? token.expiresAt > Date.now() / 1000\n : false;\n const userTokenValid = userToken\n ? userToken.expiresAt > Date.now() / 1000\n : false;\n\n const info = {\n serviceAccount: creds.serviceAccount ?? null,\n clientId: creds.clientId,\n botId: creds.botId ?? null,\n tokenValid: isValid,\n userOAuth: userToken\n ? { valid: userTokenValid, scope: userToken.scope }\n : null,\n };\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(info) }],\n };\n } catch (err) {\n return {\n content: [{ type: \"text\" as const, text: mcpErrorHint(err) }],\n isError: true,\n };\n }\n }\n );\n\n // Tool 24: 로그아웃\n server.tool(\n \"nworks_logout\",\n \"저장된 NAVER WORKS 인증 정보와 토큰을 모두 삭제합니다\",\n {},\n async () => {\n try {\n await clearCredentials();\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({\n success: true,\n message: \"인증 정보와 토큰이 모두 삭제되었습니다. 다시 사용하려면 nworks_setup tool로 재설정하세요.\",\n }),\n },\n ],\n };\n } catch (err) {\n return {\n content: [{ type: \"text\" as const, text: mcpErrorHint(err) }],\n isError: true,\n };\n }\n }\n );\n\n // Tool 25: 진단\n server.tool(\n \"nworks_doctor\",\n \"NAVER WORKS 연결 상태를 진단합니다. 인증 정보, 토큰, Private Key, API 연결을 점검합니다.\",\n {},\n async () => {\n try {\n const results = await runChecks(\"default\");\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(results) }],\n };\n } catch (err) {\n return {\n content: [{ type: \"text\" as const, text: mcpErrorHint(err) }],\n isError: true,\n };\n }\n }\n );\n}\n","export class AuthError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"AuthError\";\n }\n}\n\nexport class ApiError extends Error {\n public readonly code: string;\n public readonly statusCode: number;\n\n constructor(code: string, description: string, statusCode: number) {\n super(description);\n this.name = \"ApiError\";\n this.code = code;\n this.statusCode = statusCode;\n }\n}\n","import { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { AuthError } from \"../utils/error.js\";\n\nexport interface Credentials {\n clientId: string;\n clientSecret: string;\n serviceAccount?: string;\n privateKeyPath?: string;\n botId?: string;\n domainId?: string;\n}\n\nexport function hasServiceAccountCreds(\n creds: Credentials\n): creds is Credentials & Required<Pick<Credentials, \"serviceAccount\" | \"privateKeyPath\" | \"botId\">> {\n return !!(creds.serviceAccount && creds.privateKeyPath && creds.botId);\n}\n\nexport interface TokenData {\n accessToken: string;\n expiresAt: number;\n}\n\nexport interface UserTokenData {\n accessToken: string;\n refreshToken: string;\n expiresAt: number;\n scope: string;\n}\n\nconst CONFIG_DIR = join(homedir(), \".config\", \"nworks\");\nconst CREDENTIALS_PATH = join(CONFIG_DIR, \"credentials.json\");\nconst TOKEN_PATH = join(CONFIG_DIR, \"token.json\");\nconst USER_TOKEN_PATH = join(CONFIG_DIR, \"user-token.json\");\n\nasync function ensureConfigDir(): Promise<void> {\n if (!existsSync(CONFIG_DIR)) {\n await mkdir(CONFIG_DIR, { recursive: true });\n }\n}\n\nexport function getCredentialsFromEnv(): Credentials | null {\n const clientId = process.env[\"NWORKS_CLIENT_ID\"];\n const clientSecret = process.env[\"NWORKS_CLIENT_SECRET\"];\n\n if (!clientId || !clientSecret) return null;\n\n return {\n clientId,\n clientSecret,\n serviceAccount: process.env[\"NWORKS_SERVICE_ACCOUNT\"],\n privateKeyPath: process.env[\"NWORKS_PRIVATE_KEY_PATH\"],\n botId: process.env[\"NWORKS_BOT_ID\"],\n domainId: process.env[\"NWORKS_DOMAIN_ID\"],\n };\n}\n\nexport async function loadCredentials(\n profile = \"default\"\n): Promise<Credentials> {\n const envCreds = getCredentialsFromEnv();\n if (envCreds) return envCreds;\n\n if (!existsSync(CREDENTIALS_PATH)) {\n throw new AuthError(\n \"Not logged in. Run `nworks login` or set environment variables.\"\n );\n }\n\n const raw = await readFile(CREDENTIALS_PATH, \"utf-8\");\n const profiles = JSON.parse(raw) as Record<string, Credentials>;\n const creds = profiles[profile];\n\n if (!creds) {\n throw new AuthError(`Profile \"${profile}\" not found in credentials.`);\n }\n\n return creds;\n}\n\nexport async function saveCredentials(\n creds: Credentials,\n profile = \"default\"\n): Promise<void> {\n await ensureConfigDir();\n\n let profiles: Record<string, Credentials> = {};\n if (existsSync(CREDENTIALS_PATH)) {\n const raw = await readFile(CREDENTIALS_PATH, \"utf-8\");\n profiles = JSON.parse(raw) as Record<string, Credentials>;\n }\n\n profiles[profile] = creds;\n await writeFile(CREDENTIALS_PATH, JSON.stringify(profiles, null, 2), \"utf-8\");\n}\n\nexport async function loadToken(profile = \"default\"): Promise<TokenData | null> {\n if (!existsSync(TOKEN_PATH)) return null;\n\n const raw = await readFile(TOKEN_PATH, \"utf-8\");\n const tokens = JSON.parse(raw) as Record<string, unknown>;\n const entry = tokens[profile] as Record<string, unknown> | undefined;\n if (!entry) return null;\n\n return {\n accessToken: String(entry[\"accessToken\"]),\n expiresAt: Number(entry[\"expiresAt\"]),\n };\n}\n\nexport async function saveToken(\n token: TokenData,\n profile = \"default\"\n): Promise<void> {\n await ensureConfigDir();\n\n let tokens: Record<string, TokenData> = {};\n if (existsSync(TOKEN_PATH)) {\n const raw = await readFile(TOKEN_PATH, \"utf-8\");\n tokens = JSON.parse(raw) as Record<string, TokenData>;\n }\n\n tokens[profile] = token;\n await writeFile(TOKEN_PATH, JSON.stringify(tokens, null, 2), \"utf-8\");\n}\n\nexport async function loadUserToken(profile = \"default\"): Promise<UserTokenData | null> {\n if (!existsSync(USER_TOKEN_PATH)) return null;\n\n const raw = await readFile(USER_TOKEN_PATH, \"utf-8\");\n const tokens = JSON.parse(raw) as Record<string, unknown>;\n const entry = tokens[profile] as Record<string, unknown> | undefined;\n if (!entry) return null;\n\n return {\n accessToken: String(entry[\"accessToken\"]),\n refreshToken: String(entry[\"refreshToken\"]),\n expiresAt: Number(entry[\"expiresAt\"]),\n scope: String(entry[\"scope\"] ?? \"\"),\n };\n}\n\nexport async function saveUserToken(\n token: UserTokenData,\n profile = \"default\"\n): Promise<void> {\n await ensureConfigDir();\n\n let tokens: Record<string, UserTokenData> = {};\n if (existsSync(USER_TOKEN_PATH)) {\n const raw = await readFile(USER_TOKEN_PATH, \"utf-8\");\n tokens = JSON.parse(raw) as Record<string, UserTokenData>;\n }\n\n tokens[profile] = token;\n await writeFile(USER_TOKEN_PATH, JSON.stringify(tokens, null, 2), \"utf-8\");\n}\n\nexport async function clearCredentials(profile = \"default\"): Promise<void> {\n if (existsSync(CREDENTIALS_PATH)) {\n const raw = await readFile(CREDENTIALS_PATH, \"utf-8\");\n const profiles = JSON.parse(raw) as Record<string, Credentials>;\n delete profiles[profile];\n await writeFile(\n CREDENTIALS_PATH,\n JSON.stringify(profiles, null, 2),\n \"utf-8\"\n );\n }\n\n if (existsSync(TOKEN_PATH)) {\n const raw = await readFile(TOKEN_PATH, \"utf-8\");\n const tokens = JSON.parse(raw) as Record<string, TokenData>;\n delete tokens[profile];\n await writeFile(TOKEN_PATH, JSON.stringify(tokens, null, 2), \"utf-8\");\n }\n\n if (existsSync(USER_TOKEN_PATH)) {\n const raw = await readFile(USER_TOKEN_PATH, \"utf-8\");\n const tokens = JSON.parse(raw) as Record<string, UserTokenData>;\n delete tokens[profile];\n await writeFile(USER_TOKEN_PATH, JSON.stringify(tokens, null, 2), \"utf-8\");\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport jwt from \"jsonwebtoken\";\nimport type { Credentials } from \"./config.js\";\nimport { AuthError } from \"../utils/error.js\";\n\nexport async function createJWT(creds: Credentials): Promise<string> {\n if (!creds.serviceAccount || !creds.privateKeyPath) {\n throw new AuthError(\n \"Service Account credentials required for bot authentication.\\n\" +\n \"Run `nworks login` with --service-account and --private-key flags.\"\n );\n }\n\n const privateKey = await readFile(creds.privateKeyPath, \"utf-8\");\n\n const now = Math.floor(Date.now() / 1000);\n const payload = {\n iss: creds.clientId,\n sub: creds.serviceAccount,\n iat: now,\n exp: now + 3600,\n };\n\n return jwt.sign(payload, privateKey, { algorithm: \"RS256\" });\n}\n","import { AuthError } from \"../utils/error.js\";\nimport { loadCredentials, loadToken, saveToken } from \"./config.js\";\nimport { createJWT } from \"./jwt.js\";\n\nconst AUTH_URL = \"https://auth.worksmobile.com/oauth2/v2.0/token\";\n\nexport async function getValidToken(profile = \"default\"): Promise<string> {\n const cached = await loadToken(profile);\n\n if (cached && cached.expiresAt > Date.now() / 1000 + 300) {\n return cached.accessToken;\n }\n\n return refreshToken(profile);\n}\n\nexport async function refreshToken(profile = \"default\"): Promise<string> {\n const creds = await loadCredentials(profile);\n const assertion = await createJWT(creds);\n\n const body = new URLSearchParams({\n grant_type: \"urn:ietf:params:oauth:grant-type:jwt-bearer\",\n assertion,\n client_id: creds.clientId,\n client_secret: creds.clientSecret,\n scope: process.env[\"NWORKS_SCOPE\"] ?? \"bot bot.read user.read\",\n });\n\n const res = await fetch(AUTH_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: body.toString(),\n });\n\n if (!res.ok) {\n const text = await res.text();\n throw new AuthError(`Token exchange failed (${res.status}): ${text}`);\n }\n\n const data = (await res.json()) as {\n access_token: string;\n token_type: string;\n expires_in: number | string;\n };\n\n const expiresIn = Number(data.expires_in);\n const tokenData = {\n accessToken: data.access_token,\n expiresAt: Math.floor(Date.now() / 1000) + expiresIn,\n };\n\n await saveToken(tokenData, profile);\n return tokenData.accessToken;\n}\n","import { ApiError, AuthError } from \"../utils/error.js\";\nimport { getValidToken, refreshToken } from \"../auth/token.js\";\n\nconst BASE_URL = \"https://www.worksapis.com/v1.0\";\nconst MAX_RETRIES = 3;\n\ninterface RequestOptions {\n method: string;\n path: string;\n body?: unknown;\n profile?: string;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function request<T>(\n opts: RequestOptions,\n _retryCount = 0\n): Promise<T> {\n const { method, path, body, profile = \"default\" } = opts;\n const token = await getValidToken(profile);\n\n const url = `${BASE_URL}${path}`;\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] ${method} ${url}`);\n }\n\n const res = await fetch(url, {\n method,\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (res.status === 401 && _retryCount === 0) {\n await refreshToken(profile);\n return request<T>(opts, _retryCount + 1);\n }\n\n if (res.status === 429 && _retryCount < MAX_RETRIES) {\n const retryAfter = parseInt(res.headers.get(\"Retry-After\") ?? \"5\", 10);\n await sleep(retryAfter * 1000);\n return request<T>(opts, _retryCount + 1);\n }\n\n if (!res.ok) {\n let code = \"UNKNOWN\";\n let description = `HTTP ${res.status}`;\n\n try {\n const errorBody = (await res.json()) as {\n code?: string;\n description?: string;\n };\n code = errorBody.code ?? code;\n description = errorBody.description ?? description;\n } catch {\n // ignore\n }\n\n if (res.status === 401) {\n throw new AuthError(description);\n }\n throw new ApiError(code, description, res.status);\n }\n\n const text = await res.text();\n if (!text) {\n return undefined as T;\n }\n\n return JSON.parse(text) as T;\n}\n","import { request } from \"./client.js\";\nimport { loadCredentials } from \"../auth/config.js\";\n\nexport type MessageType = \"text\" | \"button\" | \"list\";\n\nexport interface SendOptions {\n to?: string;\n channel?: string;\n text: string;\n type?: MessageType;\n actions?: string;\n elements?: string;\n profile?: string;\n}\n\nexport interface SendResult {\n success: boolean;\n messageId?: string;\n}\n\nexport interface MemberListResult {\n members: string[];\n responseMetaData?: { nextCursor?: string };\n}\n\nfunction buildContent(opts: SendOptions): Record<string, unknown> {\n const type = opts.type ?? \"text\";\n\n if (type === \"text\") {\n return { type: \"text\", text: opts.text };\n }\n\n if (type === \"button\") {\n const actions = opts.actions ? JSON.parse(opts.actions) as unknown[] : [];\n return {\n type: \"button_template\",\n contentText: opts.text,\n actions,\n };\n }\n\n if (type === \"list\") {\n const elements = opts.elements ? JSON.parse(opts.elements) as unknown[] : [];\n return {\n type: \"list_template\",\n coverData: { text: opts.text },\n elements,\n };\n }\n\n return { type: \"text\", text: opts.text };\n}\n\nexport async function send(opts: SendOptions): Promise<SendResult> {\n const profile = opts.profile ?? \"default\";\n const creds = await loadCredentials(profile);\n\n if (!creds.botId) {\n throw new Error(\n \"Bot ID is required for sending messages.\\n\" +\n \"Run `nworks login` with --bot-id flag to set up bot credentials.\"\n );\n }\n\n const content = buildContent(opts);\n const body = { content };\n\n if (opts.to) {\n const result = await request<{ messageId?: string }>({\n method: \"POST\",\n path: `/bots/${creds.botId}/users/${opts.to}/messages`,\n body,\n profile,\n });\n return { success: true, messageId: result?.messageId };\n }\n if (opts.channel) {\n const result = await request<{ messageId?: string }>({\n method: \"POST\",\n path: `/bots/${creds.botId}/channels/${opts.channel}/messages`,\n body,\n profile,\n });\n return { success: true, messageId: result?.messageId };\n }\n\n throw new Error(\"Either --to (userId) or --channel (channelId) is required.\");\n}\n\n\nexport async function listMembers(\n channelId: string,\n profile = \"default\"\n): Promise<MemberListResult> {\n const creds = await loadCredentials(profile);\n\n if (!creds.botId) {\n throw new Error(\n \"Bot ID is required for listing channel members.\\n\" +\n \"Run `nworks login` with --bot-id flag to set up bot credentials.\"\n );\n }\n\n const result = await request<{ members: string[]; responseMetaData?: { nextCursor?: string } }>({\n method: \"GET\",\n path: `/bots/${creds.botId}/channels/${channelId}/members`,\n profile,\n });\n return { members: result.members ?? [], responseMetaData: result.responseMetaData };\n}\n","import { request } from \"./client.js\";\n\nexport interface User {\n userId: string;\n userName?: {\n lastName?: string;\n firstName?: string;\n };\n email?: string;\n organizations?: Array<{\n organizationName?: string;\n primary?: boolean;\n }>;\n isAdministrator?: boolean;\n isDeleted?: boolean;\n}\n\nexport interface UserListResult {\n users: User[];\n responseMetaData?: { nextCursor?: string };\n}\n\nexport async function listUsers(\n profile = \"default\"\n): Promise<UserListResult> {\n const result = await request<{\n users: User[];\n responseMetaData?: { nextCursor?: string };\n }>({\n method: \"GET\",\n path: \"/users\",\n profile,\n });\n return { users: result.users ?? [], responseMetaData: result.responseMetaData };\n}\n","import { randomUUID } from \"node:crypto\";\nimport { ApiError, AuthError } from \"../utils/error.js\";\nimport { getValidUserToken } from \"../auth/token-user.js\";\n\nconst BASE_URL = \"https://www.worksapis.com/v1.0\";\n\nexport interface CalendarEvent {\n eventId: string;\n summary: string;\n description?: string;\n location?: string;\n start: { date?: string; dateTime?: string; timeZone?: string };\n end: { date?: string; dateTime?: string; timeZone?: string };\n transparency?: string;\n visibility?: string;\n attendees?: Array<{ email?: string; displayName?: string }>;\n createdTime?: { dateTime?: string; timeZone?: string };\n updatedTime?: { dateTime?: string; timeZone?: string };\n viewUrl?: string;\n}\n\nexport interface EventListResult {\n events: Array<{\n eventComponents: CalendarEvent[];\n organizerCalendarId?: string;\n }>;\n}\n\nexport interface CreateEventOptions {\n summary: string;\n start: string;\n end: string;\n timeZone?: string;\n description?: string;\n location?: string;\n attendees?: Array<{ email: string; displayName?: string }>;\n transparency?: \"OPAQUE\" | \"TRANSPARENT\";\n visibility?: \"PUBLIC\" | \"PRIVATE\";\n sendNotification?: boolean;\n userId?: string;\n profile?: string;\n}\n\nexport interface UpdateEventOptions {\n eventId: string;\n summary?: string;\n start?: string;\n end?: string;\n timeZone?: string;\n description?: string;\n location?: string;\n attendees?: Array<{ email: string; displayName?: string }>;\n transparency?: \"OPAQUE\" | \"TRANSPARENT\";\n visibility?: \"PUBLIC\" | \"PRIVATE\";\n sendNotification?: boolean;\n userId?: string;\n profile?: string;\n}\n\nasync function authedFetch(\n url: string,\n init: RequestInit,\n profile: string\n): Promise<Response> {\n const token = await getValidUserToken(profile);\n const headers = new Headers(init.headers);\n headers.set(\"Authorization\", `Bearer ${token}`);\n return fetch(url, { ...init, headers });\n}\n\nasync function handleError(res: Response): Promise<never> {\n if (res.status === 401) {\n throw new AuthError(\"User token expired. Run `nworks login --user --scope calendar` again.\");\n }\n let code = \"UNKNOWN\";\n let description = `HTTP ${res.status}`;\n try {\n const body = (await res.json()) as { code?: string; description?: string };\n code = body.code ?? code;\n description = body.description ?? description;\n } catch {\n // ignore\n }\n throw new ApiError(code, description, res.status);\n}\n\nfunction generateEventId(): string {\n return `event-${randomUUID()}`;\n}\n\n/** 초가 없으면 :00 추가 (API 요구사항) */\nfunction normalizeDateTime(dt: string): string {\n const match = dt.match(/^(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2})([+-]\\d{2}:\\d{2}|Z)?$/);\n if (match) {\n return `${match[1]}:00${match[2] ?? \"\"}`;\n }\n return dt;\n}\n\nexport async function listEvents(\n fromDateTime: string,\n untilDateTime: string,\n userId = \"me\",\n profile = \"default\"\n): Promise<EventListResult> {\n const from = encodeURIComponent(fromDateTime);\n const until = encodeURIComponent(untilDateTime);\n\n const url = `${BASE_URL}/users/${userId}/calendar/events?fromDateTime=${from}&untilDateTime=${until}`;\n\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] GET ${url}`);\n }\n\n const res = await authedFetch(url, { method: \"GET\" }, profile);\n if (!res.ok) return handleError(res);\n\n const data = (await res.json()) as EventListResult;\n return { events: data.events ?? [] };\n}\n\nexport async function createEvent(\n opts: CreateEventOptions\n): Promise<{ eventComponents: CalendarEvent[]; organizerCalendarId?: string }> {\n const userId = opts.userId ?? \"me\";\n const profile = opts.profile ?? \"default\";\n const timeZone = opts.timeZone ?? \"Asia/Seoul\";\n\n const eventId = generateEventId();\n\n const eventComponent: Record<string, unknown> = {\n eventId,\n summary: opts.summary,\n start: { dateTime: normalizeDateTime(opts.start), timeZone },\n end: { dateTime: normalizeDateTime(opts.end), timeZone },\n };\n if (opts.description) eventComponent.description = opts.description;\n if (opts.location) eventComponent.location = opts.location;\n if (opts.transparency) eventComponent.transparency = opts.transparency;\n if (opts.visibility) eventComponent.visibility = opts.visibility;\n if (opts.attendees) {\n eventComponent.attendees = opts.attendees.map((a) => ({\n email: a.email,\n displayName: a.displayName ?? \"\",\n partstat: \"NEEDS-ACTION\",\n isOptional: false,\n isResource: false,\n }));\n }\n\n const body = {\n eventComponents: [eventComponent],\n sendNotification: opts.sendNotification ?? false,\n };\n\n const url = `${BASE_URL}/users/${userId}/calendar/events`;\n\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] POST ${url}`);\n console.error(`[nworks] Body: ${JSON.stringify(body, null, 2)}`);\n }\n\n const res = await authedFetch(\n url,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n },\n profile\n );\n\n if (res.status === 201) {\n return (await res.json()) as { eventComponents: CalendarEvent[]; organizerCalendarId?: string };\n }\n if (!res.ok) return handleError(res);\n return (await res.json()) as { eventComponents: CalendarEvent[]; organizerCalendarId?: string };\n}\n\nexport async function getEvent(\n eventId: string,\n userId = \"me\",\n profile = \"default\"\n): Promise<CalendarEvent> {\n const url = `${BASE_URL}/users/${userId}/calendar/events/${eventId}`;\n\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] GET ${url}`);\n }\n\n const res = await authedFetch(url, { method: \"GET\" }, profile);\n if (!res.ok) return handleError(res);\n\n const data = (await res.json()) as { eventComponents: CalendarEvent[] };\n const event = data.eventComponents[0];\n if (!event) throw new ApiError(\"NOT_FOUND\", \"Event not found\", 404);\n return event;\n}\n\nexport async function updateEvent(\n opts: UpdateEventOptions\n): Promise<void> {\n const userId = opts.userId ?? \"me\";\n const profile = opts.profile ?? \"default\";\n const timeZone = opts.timeZone ?? \"Asia/Seoul\";\n\n const existing = await getEvent(opts.eventId, userId, profile);\n\n const eventComponent: Record<string, unknown> = {\n eventId: opts.eventId,\n summary: opts.summary ?? existing.summary,\n start: opts.start\n ? { dateTime: normalizeDateTime(opts.start), timeZone }\n : existing.start,\n end: opts.end\n ? { dateTime: normalizeDateTime(opts.end), timeZone }\n : existing.end,\n };\n if (opts.description !== undefined) eventComponent.description = opts.description;\n else if (existing.description) eventComponent.description = existing.description;\n if (opts.location !== undefined) eventComponent.location = opts.location;\n else if (existing.location) eventComponent.location = existing.location;\n if (opts.transparency !== undefined) eventComponent.transparency = opts.transparency;\n if (opts.visibility !== undefined) eventComponent.visibility = opts.visibility;\n if (opts.attendees !== undefined) {\n eventComponent.attendees = opts.attendees.map((a) => ({\n email: a.email,\n displayName: a.displayName ?? \"\",\n partstat: \"NEEDS-ACTION\",\n isOptional: false,\n isResource: false,\n }));\n } else if (existing.attendees) {\n eventComponent.attendees = existing.attendees;\n }\n\n const body = {\n eventComponents: [eventComponent],\n sendNotification: opts.sendNotification ?? false,\n };\n\n const url = `${BASE_URL}/users/${userId}/calendar/events/${opts.eventId}`;\n\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] PUT ${url}`);\n console.error(`[nworks] Body: ${JSON.stringify(body, null, 2)}`);\n }\n\n const res = await authedFetch(\n url,\n {\n method: \"PUT\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n },\n profile\n );\n\n if (!res.ok) return handleError(res);\n}\n\nexport async function deleteEvent(\n eventId: string,\n userId = \"me\",\n sendNotification = false,\n profile = \"default\"\n): Promise<void> {\n const params = new URLSearchParams();\n params.set(\"sendNotification\", String(sendNotification));\n\n const url = `${BASE_URL}/users/${userId}/calendar/events/${eventId}?${params.toString()}`;\n\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] DELETE ${url}`);\n }\n\n const res = await authedFetch(url, { method: \"DELETE\" }, profile);\n\n if (res.status === 204) return;\n if (!res.ok) return handleError(res);\n}\n","import { createServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport { URL } from \"node:url\";\nimport { AuthError } from \"../utils/error.js\";\nimport { loadCredentials } from \"./config.js\";\n\nconst AUTH_URL = \"https://auth.worksmobile.com/oauth2/v2.0/authorize\";\nconst TOKEN_URL = \"https://auth.worksmobile.com/oauth2/v2.0/token\";\nconst REDIRECT_PORT = 9876;\nconst REDIRECT_URI = `http://localhost:${REDIRECT_PORT}/callback`;\n\ninterface UserTokenResult {\n accessToken: string;\n refreshToken: string;\n expiresAt: number;\n scope: string;\n}\n\nexport function buildAuthorizeUrl(clientId: string, scope: string, state: string): string {\n const params = new URLSearchParams({\n client_id: clientId,\n redirect_uri: REDIRECT_URI,\n scope,\n response_type: \"code\",\n state,\n });\n return `${AUTH_URL}?${params.toString()}`;\n}\n\n/**\n * Start local HTTP server and wait for OAuth callback with auth code.\n * Then exchange code for tokens.\n */\nexport async function startUserOAuthFlow(\n _scope: string,\n profile = \"default\"\n): Promise<UserTokenResult> {\n const creds = await loadCredentials(profile);\n const code = await waitForAuthCode();\n\n return exchangeCodeForToken(code, creds.clientId, creds.clientSecret);\n}\n\nfunction waitForAuthCode(): Promise<string> {\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n server.close();\n reject(new AuthError(\"OAuth login timed out (120s). Try again.\"));\n }, 120_000);\n\n const server = createServer((req: IncomingMessage, res: ServerResponse) => {\n const url = new URL(req.url ?? \"/\", `http://localhost:${REDIRECT_PORT}`);\n\n if (url.pathname !== \"/callback\") {\n res.writeHead(404);\n res.end(\"Not found\");\n return;\n }\n\n const code = url.searchParams.get(\"code\");\n const error = url.searchParams.get(\"error\");\n\n if (error) {\n res.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" });\n res.end(\"<h2>로그인 실패</h2><p>이 창을 닫아도 됩니다.</p>\");\n clearTimeout(timeout);\n server.close();\n reject(new AuthError(`OAuth error: ${error}`));\n return;\n }\n\n if (!code) {\n res.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n res.end(\"<h2>잘못된 요청</h2><p>Authorization code가 없습니다.</p>\");\n clearTimeout(timeout);\n server.close();\n reject(new AuthError(\"Missing authorization code in callback.\"));\n return;\n }\n\n res.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" });\n res.end(\"<h2>로그인 성공!</h2><p>이 창을 닫고 터미널로 돌아가세요.</p>\");\n clearTimeout(timeout);\n server.close();\n resolve(code);\n });\n\n server.listen(REDIRECT_PORT, () => {\n // Server ready — caller opens browser\n });\n\n server.on(\"error\", (err) => {\n clearTimeout(timeout);\n reject(new AuthError(`Failed to start callback server on port ${REDIRECT_PORT}: ${err.message}`));\n });\n });\n}\n\nasync function exchangeCodeForToken(\n code: string,\n clientId: string,\n clientSecret: string\n): Promise<UserTokenResult> {\n const body = new URLSearchParams({\n grant_type: \"authorization_code\",\n code,\n client_id: clientId,\n client_secret: clientSecret,\n redirect_uri: REDIRECT_URI,\n });\n\n const res = await fetch(TOKEN_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: body.toString(),\n });\n\n if (!res.ok) {\n const text = await res.text();\n throw new AuthError(`Token exchange failed (${res.status}): ${text}`);\n }\n\n const data = (await res.json()) as {\n access_token: string;\n refresh_token: string;\n expires_in: number | string;\n scope: string;\n };\n\n return {\n accessToken: data.access_token,\n refreshToken: data.refresh_token,\n expiresAt: Math.floor(Date.now() / 1000) + Number(data.expires_in),\n scope: data.scope,\n };\n}\n\nexport async function refreshUserToken(\n refreshToken: string,\n profile = \"default\"\n): Promise<UserTokenResult> {\n const creds = await loadCredentials(profile);\n\n const body = new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: refreshToken,\n client_id: creds.clientId,\n client_secret: creds.clientSecret,\n });\n\n const res = await fetch(TOKEN_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: body.toString(),\n });\n\n if (!res.ok) {\n const text = await res.text();\n throw new AuthError(`Token refresh failed (${res.status}): ${text}`);\n }\n\n const data = (await res.json()) as {\n access_token: string;\n refresh_token?: string;\n expires_in: number | string;\n scope: string;\n };\n\n return {\n accessToken: data.access_token,\n refreshToken: data.refresh_token ?? refreshToken,\n expiresAt: Math.floor(Date.now() / 1000) + Number(data.expires_in),\n scope: data.scope,\n };\n}\n\n/**\n * Start OAuth callback server in background and return token when callback arrives.\n * Used by MCP tool to fire-and-forget while returning the auth URL immediately.\n */\nexport function startOAuthCallbackServer(\n clientId: string,\n clientSecret: string,\n): Promise<UserTokenResult> {\n return waitForAuthCode().then((code) =>\n exchangeCodeForToken(code, clientId, clientSecret)\n );\n}\n\nexport { REDIRECT_URI };\n","import { AuthError } from \"../utils/error.js\";\nimport { loadUserToken, saveUserToken } from \"./config.js\";\nimport { refreshUserToken } from \"./oauth-user.js\";\n\nexport async function getValidUserToken(profile = \"default\"): Promise<string> {\n const cached = await loadUserToken(profile);\n\n if (!cached) {\n throw new AuthError(\n \"User OAuth token not found. Run `nworks login --user` first.\"\n );\n }\n\n if (cached.expiresAt > Date.now() / 1000 + 300) {\n return cached.accessToken;\n }\n\n const refreshed = await refreshUserToken(cached.refreshToken, profile);\n await saveUserToken(refreshed, profile);\n return refreshed.accessToken;\n}\n","import { readFile, stat } from \"node:fs/promises\";\nimport { basename } from \"node:path\";\nimport { ApiError, AuthError } from \"../utils/error.js\";\nimport { getValidUserToken } from \"../auth/token-user.js\";\n\nconst BASE_URL = \"https://www.worksapis.com/v1.0\";\n\nexport interface DriveFile {\n fileId: string;\n parentFileId?: string;\n fileName: string;\n fileSize: number;\n filePath: string;\n fileType: string;\n createdTime: string;\n modifiedTime: string;\n accessedTime?: string;\n statuses?: string[];\n shared?: boolean;\n}\n\nexport interface FileListResult {\n files: DriveFile[];\n responseMetaData?: { nextCursor?: string };\n}\n\nexport interface UploadUrlResult {\n uploadUrl: string;\n offset: number;\n}\n\nexport interface UploadResult {\n fileId: string;\n fileName: string;\n fileSize: string;\n filePath: string;\n fileType: string;\n}\n\nasync function authedFetch(\n url: string,\n init: RequestInit,\n profile: string\n): Promise<Response> {\n const token = await getValidUserToken(profile);\n const headers = new Headers(init.headers);\n headers.set(\"Authorization\", `Bearer ${token}`);\n return fetch(url, { ...init, headers });\n}\n\nasync function handleError(res: Response): Promise<never> {\n if (res.status === 401) {\n throw new AuthError(\"User token expired. Run `nworks login --user --scope file` again.\");\n }\n let code = \"UNKNOWN\";\n let description = `HTTP ${res.status}`;\n try {\n const body = (await res.json()) as { code?: string; description?: string };\n code = body.code ?? code;\n description = body.description ?? description;\n } catch {\n // ignore\n }\n throw new ApiError(code, description, res.status);\n}\n\nexport async function listFiles(\n userId = \"me\",\n folderId?: string,\n count = 20,\n cursor?: string,\n profile = \"default\"\n): Promise<FileListResult> {\n const base = `${BASE_URL}/users/${userId}/drive/files`;\n const path = folderId ? `${base}/${folderId}/children` : base;\n\n const params = new URLSearchParams();\n params.set(\"count\", String(count));\n if (cursor) params.set(\"cursor\", cursor);\n\n const url = `${path}?${params.toString()}`;\n\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] GET ${url}`);\n }\n\n const res = await authedFetch(url, { method: \"GET\" }, profile);\n\n if (!res.ok) return handleError(res);\n\n const data = (await res.json()) as FileListResult;\n return { files: data.files ?? [], responseMetaData: data.responseMetaData };\n}\n\nexport async function uploadFile(\n localPath: string,\n userId = \"me\",\n folderId?: string,\n overwrite = false,\n profile = \"default\"\n): Promise<UploadResult> {\n const fileName = basename(localPath);\n const fileStat = await stat(localPath);\n const fileSize = fileStat.size;\n\n const base = `${BASE_URL}/users/${userId}/drive/files`;\n const createUrl = folderId ? `${base}/${folderId}` : base;\n\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] POST ${createUrl} (create upload URL)`);\n }\n\n const createRes = await authedFetch(\n createUrl,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ fileName, fileSize, overwrite }),\n },\n profile\n );\n\n if (!createRes.ok) return handleError(createRes);\n\n const { uploadUrl } = (await createRes.json()) as UploadUrlResult;\n const fileBuffer = await readFile(localPath);\n const boundary = `----nworks${Date.now()}`;\n\n const header = Buffer.from(\n `--${boundary}\\r\\n` +\n `Content-Disposition: form-data; name=\"Filedata\"; filename=\"${fileName}\"\\r\\n` +\n `Content-Type: application/octet-stream\\r\\n\\r\\n`\n );\n const footer = Buffer.from(`\\r\\n--${boundary}--\\r\\n`);\n const body = Buffer.concat([header, fileBuffer, footer]);\n\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] POST ${uploadUrl} (upload content, ${fileSize} bytes)`);\n }\n\n const uploadRes = await authedFetch(\n uploadUrl,\n {\n method: \"POST\",\n headers: { \"Content-Type\": `multipart/form-data; boundary=${boundary}` },\n body,\n },\n profile\n );\n\n if (!uploadRes.ok) return handleError(uploadRes);\n\n return (await uploadRes.json()) as UploadResult;\n}\n\nexport async function uploadBuffer(\n fileBuffer: Buffer,\n fileName: string,\n userId = \"me\",\n folderId?: string,\n overwrite = false,\n profile = \"default\"\n): Promise<UploadResult> {\n const fileSize = fileBuffer.length;\n\n const base = `${BASE_URL}/users/${userId}/drive/files`;\n const createUrl = folderId ? `${base}/${folderId}` : base;\n\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] POST ${createUrl} (create upload URL for buffer)`);\n }\n\n const createRes = await authedFetch(\n createUrl,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ fileName, fileSize, overwrite }),\n },\n profile\n );\n\n if (!createRes.ok) return handleError(createRes);\n\n const { uploadUrl } = (await createRes.json()) as UploadUrlResult;\n const boundary = `----nworks${Date.now()}`;\n\n const header = Buffer.from(\n `--${boundary}\\r\\n` +\n `Content-Disposition: form-data; name=\"Filedata\"; filename=\"${fileName}\"\\r\\n` +\n `Content-Type: application/octet-stream\\r\\n\\r\\n`\n );\n const footer = Buffer.from(`\\r\\n--${boundary}--\\r\\n`);\n const body = Buffer.concat([header, fileBuffer, footer]);\n\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] POST ${uploadUrl} (upload buffer, ${fileSize} bytes)`);\n }\n\n const uploadRes = await authedFetch(\n uploadUrl,\n {\n method: \"POST\",\n headers: { \"Content-Type\": `multipart/form-data; boundary=${boundary}` },\n body,\n },\n profile\n );\n\n if (!uploadRes.ok) return handleError(uploadRes);\n\n return (await uploadRes.json()) as UploadResult;\n}\n\nexport async function downloadFile(\n fileId: string,\n userId = \"me\",\n profile = \"default\"\n): Promise<{ buffer: Buffer; fileName?: string }> {\n const url = `${BASE_URL}/users/${userId}/drive/files/${fileId}/download`;\n\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] GET ${url} (get download URL)`);\n }\n\n const redirectRes = await authedFetch(\n url,\n { method: \"GET\", redirect: \"manual\" },\n profile\n );\n\n if (redirectRes.status === 401) {\n throw new AuthError(\"User token expired. Run `nworks login --user --scope file` again.\");\n }\n\n const location = redirectRes.headers.get(\"location\");\n if (!location) {\n if (!redirectRes.ok) return handleError(redirectRes);\n throw new ApiError(\"NO_REDIRECT\", \"No download URL returned\", redirectRes.status);\n }\n\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] GET ${location} (download content)`);\n }\n\n const downloadRes = await authedFetch(location, { method: \"GET\" }, profile);\n\n if (!downloadRes.ok) return handleError(downloadRes);\n\n const arrayBuffer = await downloadRes.arrayBuffer();\n const buffer = Buffer.from(arrayBuffer);\n\n const disposition = downloadRes.headers.get(\"content-disposition\");\n let fileName: string | undefined;\n if (disposition) {\n const match = disposition.match(/filename\\*?=(?:UTF-8''|\"?)([^\";]+)/i);\n if (match?.[1]) {\n fileName = decodeURIComponent(match[1].replace(/\"/g, \"\"));\n }\n }\n\n return { buffer, fileName };\n}\n","import { ApiError, AuthError } from \"../utils/error.js\";\nimport { getValidUserToken } from \"../auth/token-user.js\";\n\nconst BASE_URL = \"https://www.worksapis.com/v1.0\";\n\nexport interface MailAddress {\n name?: string;\n email: string;\n}\n\nexport interface SendMailOptions {\n to: string;\n cc?: string;\n bcc?: string;\n subject: string;\n body?: string;\n contentType?: \"html\" | \"text\";\n userId?: string;\n profile?: string;\n}\n\nexport interface MailSummary {\n mailId: number;\n folderId: number;\n status: string;\n from: MailAddress;\n to: MailAddress[];\n subject: string;\n receivedTime: string;\n sentTime?: string;\n size: number;\n isImportant?: boolean;\n attachCount?: number;\n}\n\nexport interface MailListResult {\n mails: MailSummary[];\n unreadCount?: number;\n folderName?: string;\n totalCount?: number;\n responseMetaData?: { nextCursor?: string };\n}\n\nexport interface MailDetail {\n mail: {\n mailId: number;\n folderId: number;\n status: number;\n from: MailAddress;\n to: MailAddress[];\n cc?: MailAddress[];\n bcc?: MailAddress[];\n subject: string;\n body: string;\n receivedTime: string;\n sentTime?: string;\n size: number;\n securityLevel?: string;\n };\n attachments?: Array<{\n attachmentId: number;\n contentType: string;\n filename: string;\n size: number;\n }>;\n}\n\nasync function authedFetch(\n url: string,\n init: RequestInit,\n profile: string\n): Promise<Response> {\n const token = await getValidUserToken(profile);\n const headers = new Headers(init.headers);\n headers.set(\"Authorization\", `Bearer ${token}`);\n return fetch(url, { ...init, headers });\n}\n\nasync function handleError(res: Response): Promise<never> {\n if (res.status === 401) {\n throw new AuthError(\"User token expired. Run `nworks login --user --scope mail` again.\");\n }\n let code = \"UNKNOWN\";\n let description = `HTTP ${res.status}`;\n try {\n const body = (await res.json()) as { code?: string; description?: string };\n code = body.code ?? code;\n description = body.description ?? description;\n } catch {\n // ignore\n }\n throw new ApiError(code, description, res.status);\n}\n\nexport async function sendMail(opts: SendMailOptions): Promise<void> {\n const userId = opts.userId ?? \"me\";\n const profile = opts.profile ?? \"default\";\n const url = `${BASE_URL}/users/${userId}/mail`;\n\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] POST ${url}`);\n }\n\n const body: Record<string, unknown> = {\n to: opts.to,\n subject: opts.subject,\n };\n if (opts.body !== undefined) body.body = opts.body;\n if (opts.cc) body.cc = opts.cc;\n if (opts.bcc) body.bcc = opts.bcc;\n if (opts.contentType) body.contentType = opts.contentType;\n\n const res = await authedFetch(\n url,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n },\n profile\n );\n\n if (res.status === 202) return;\n\n if (!res.ok) return handleError(res);\n}\n\nexport async function listMails(\n folderId = 0,\n userId = \"me\",\n count = 30,\n cursor?: string,\n isUnread?: boolean,\n profile = \"default\"\n): Promise<MailListResult> {\n const params = new URLSearchParams();\n params.set(\"count\", String(count));\n if (cursor) params.set(\"cursor\", cursor);\n if (isUnread) params.set(\"isUnread\", \"true\");\n\n const url = `${BASE_URL}/users/${userId}/mail/mailfolders/${folderId}/children?${params.toString()}`;\n\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] GET ${url}`);\n }\n\n const res = await authedFetch(url, { method: \"GET\" }, profile);\n\n if (!res.ok) return handleError(res);\n\n const data = (await res.json()) as MailListResult;\n return {\n mails: data.mails ?? [],\n unreadCount: data.unreadCount,\n folderName: data.folderName,\n totalCount: data.totalCount,\n responseMetaData: data.responseMetaData,\n };\n}\n\nexport async function readMail(\n mailId: number,\n userId = \"me\",\n profile = \"default\"\n): Promise<MailDetail> {\n const url = `${BASE_URL}/users/${userId}/mail/${mailId}`;\n\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] GET ${url}`);\n }\n\n const res = await authedFetch(url, { method: \"GET\" }, profile);\n\n if (!res.ok) return handleError(res);\n\n return (await res.json()) as MailDetail;\n}\n","import { ApiError, AuthError } from \"../utils/error.js\";\nimport { getValidUserToken } from \"../auth/token-user.js\";\n\nconst BASE_URL = \"https://www.worksapis.com/v1.0\";\n\nexport interface Assignee {\n assigneeId: string;\n assigneeName?: string;\n status: \"TODO\" | \"DONE\";\n}\n\nexport interface Task {\n taskId: string;\n title: string;\n content: string;\n status: \"TODO\" | \"DONE\";\n assignorId: string;\n assignorName?: string;\n assignees: Assignee[];\n completionCondition: \"ANY_ONE\" | \"MUST_ALL\";\n dueDate: string | null;\n createdTime: string;\n modifiedTime: string;\n}\n\nexport interface TaskListResult {\n tasks: Task[];\n responseMetaData?: { nextCursor?: string };\n}\n\nexport interface TaskCategory {\n categoryId: string;\n categoryName: string;\n}\n\nexport interface CreateTaskOptions {\n title: string;\n content?: string;\n dueDate?: string;\n categoryId?: string;\n assignorId?: string;\n assigneeIds?: string[];\n userId?: string;\n profile?: string;\n}\n\nexport interface UpdateTaskOptions {\n taskId: string;\n title?: string;\n content?: string;\n dueDate?: string | null;\n profile?: string;\n}\n\nasync function authedFetch(\n url: string,\n init: RequestInit,\n profile: string\n): Promise<Response> {\n const token = await getValidUserToken(profile);\n const headers = new Headers(init.headers);\n headers.set(\"Authorization\", `Bearer ${token}`);\n return fetch(url, { ...init, headers });\n}\n\nasync function handleError(res: Response): Promise<never> {\n if (res.status === 401) {\n throw new AuthError(\"User token expired. Run `nworks login --user --scope task` again.\");\n }\n let code = \"UNKNOWN\";\n let description = `HTTP ${res.status}`;\n try {\n const body = (await res.json()) as { code?: string; description?: string };\n code = body.code ?? code;\n description = body.description ?? description;\n } catch {\n // ignore\n }\n throw new ApiError(code, description, res.status);\n}\n\nasync function resolveUserId(\n userId: string,\n profile: string\n): Promise<string> {\n if (userId !== \"me\") return userId;\n\n const url = `${BASE_URL}/users/me`;\n const res = await authedFetch(url, { method: \"GET\" }, profile);\n if (!res.ok) return handleError(res);\n\n const data = (await res.json()) as { userId: string };\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] Resolved \"me\" → ${data.userId}`);\n }\n return data.userId;\n}\n\nexport async function listCategories(\n userId = \"me\",\n profile = \"default\"\n): Promise<TaskCategory[]> {\n const url = `${BASE_URL}/users/${userId}/task-categories`;\n\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] GET ${url}`);\n }\n\n const res = await authedFetch(url, { method: \"GET\" }, profile);\n if (!res.ok) return handleError(res);\n\n const data = (await res.json()) as { taskCategories: TaskCategory[] };\n return data.taskCategories ?? [];\n}\n\nexport async function listTasks(\n categoryId = \"default\",\n userId = \"me\",\n count = 50,\n cursor?: string,\n status: \"TODO\" | \"ALL\" = \"ALL\",\n profile = \"default\"\n): Promise<TaskListResult> {\n const params = new URLSearchParams();\n params.set(\"categoryId\", categoryId);\n params.set(\"count\", String(count));\n params.set(\"status\", status);\n if (cursor) params.set(\"cursor\", cursor);\n\n const url = `${BASE_URL}/users/${userId}/tasks?${params.toString()}`;\n\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] GET ${url}`);\n }\n\n const res = await authedFetch(url, { method: \"GET\" }, profile);\n if (!res.ok) return handleError(res);\n\n const data = (await res.json()) as TaskListResult;\n return { tasks: data.tasks ?? [], responseMetaData: data.responseMetaData };\n}\n\nexport async function getTask(\n taskId: string,\n profile = \"default\"\n): Promise<Task> {\n const url = `${BASE_URL}/tasks/${taskId}`;\n\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] GET ${url}`);\n }\n\n const res = await authedFetch(url, { method: \"GET\" }, profile);\n if (!res.ok) return handleError(res);\n\n return (await res.json()) as Task;\n}\n\nexport async function createTask(opts: CreateTaskOptions): Promise<Task> {\n const userId = opts.userId ?? \"me\";\n const profile = opts.profile ?? \"default\";\n\n const resolvedUserId = await resolveUserId(userId, profile);\n const assignorId = opts.assignorId ?? resolvedUserId;\n const assigneeIds = opts.assigneeIds ?? [resolvedUserId];\n\n const body: Record<string, unknown> = {\n assignorId,\n assignees: assigneeIds.map((id) => ({ assigneeId: id, status: \"TODO\" })),\n title: opts.title,\n content: opts.content ?? \"\",\n completionCondition: \"ANY_ONE\",\n };\n if (opts.dueDate) body.dueDate = opts.dueDate;\n if (opts.categoryId) body.categoryId = opts.categoryId;\n\n const url = `${BASE_URL}/users/${userId}/tasks`;\n\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] POST ${url}`);\n console.error(`[nworks] Body: ${JSON.stringify(body, null, 2)}`);\n }\n\n const res = await authedFetch(\n url,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n },\n profile\n );\n\n if (res.status === 201) {\n return (await res.json()) as Task;\n }\n if (!res.ok) return handleError(res);\n return (await res.json()) as Task;\n}\n\nexport async function updateTask(opts: UpdateTaskOptions): Promise<Task> {\n const profile = opts.profile ?? \"default\";\n\n const body: Record<string, unknown> = {};\n if (opts.title !== undefined) body.title = opts.title;\n if (opts.content !== undefined) body.content = opts.content;\n if (opts.dueDate !== undefined) body.dueDate = opts.dueDate;\n\n const url = `${BASE_URL}/tasks/${opts.taskId}`;\n\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] PATCH ${url}`);\n }\n\n const res = await authedFetch(\n url,\n {\n method: \"PATCH\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n },\n profile\n );\n\n if (!res.ok) return handleError(res);\n return (await res.json()) as Task;\n}\n\nexport async function completeTask(\n taskId: string,\n profile = \"default\"\n): Promise<void> {\n const url = `${BASE_URL}/tasks/${taskId}/complete`;\n\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] POST ${url}`);\n }\n\n const res = await authedFetch(\n url,\n { method: \"POST\" },\n profile\n );\n\n if (res.status === 204) return;\n if (!res.ok) return handleError(res);\n}\n\nexport async function incompleteTask(\n taskId: string,\n profile = \"default\"\n): Promise<void> {\n const url = `${BASE_URL}/tasks/${taskId}/incomplete`;\n\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] POST ${url}`);\n }\n\n const res = await authedFetch(\n url,\n { method: \"POST\" },\n profile\n );\n\n if (res.status === 204) return;\n if (!res.ok) return handleError(res);\n}\n\nexport async function deleteTask(\n taskId: string,\n profile = \"default\"\n): Promise<void> {\n const url = `${BASE_URL}/tasks/${taskId}`;\n\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] DELETE ${url}`);\n }\n\n const res = await authedFetch(\n url,\n { method: \"DELETE\" },\n profile\n );\n\n if (res.status === 204) return;\n if (!res.ok) return handleError(res);\n}\n","import { ApiError, AuthError } from \"../utils/error.js\";\nimport { getValidUserToken } from \"../auth/token-user.js\";\n\nconst BASE_URL = \"https://www.worksapis.com/v1.0\";\n\nexport interface Board {\n boardId: string;\n boardName: string;\n description?: string;\n createdTime?: string;\n domainId?: string;\n}\n\nexport interface BoardListResult {\n boards: Board[];\n responseMetaData?: { nextCursor?: string };\n}\n\nexport interface Post {\n boardId: string;\n postId: string;\n title: string;\n body?: string;\n readCount?: number;\n userName?: string;\n userId?: string;\n createdTime?: string;\n updatedTime?: string;\n commentCount?: number;\n enableComment?: boolean;\n}\n\nexport interface PostListResult {\n posts: Post[];\n responseMetaData?: { nextCursor?: string };\n}\n\nexport interface CreatePostOptions {\n boardId: string;\n title: string;\n body?: string;\n enableComment?: boolean;\n sendNotifications?: boolean;\n profile?: string;\n}\n\nasync function authedFetch(\n url: string,\n init: RequestInit,\n profile: string\n): Promise<Response> {\n const token = await getValidUserToken(profile);\n const headers = new Headers(init.headers);\n headers.set(\"Authorization\", `Bearer ${token}`);\n return fetch(url, { ...init, headers });\n}\n\nasync function handleError(res: Response): Promise<never> {\n if (res.status === 401) {\n throw new AuthError(\"User token expired. Run `nworks login --user --scope board` again.\");\n }\n let code = \"UNKNOWN\";\n let description = `HTTP ${res.status}`;\n try {\n const body = (await res.json()) as { code?: string; description?: string };\n code = body.code ?? code;\n description = body.description ?? description;\n } catch {\n // ignore\n }\n throw new ApiError(code, description, res.status);\n}\n\n/** int64 ID 필드의 정밀도 손실 방지를 위해 문자열로 변환 후 파싱 */\nfunction safeParseJson<T>(text: string): T {\n const safe = text.replace(\n /\"((?:board|post|domain|user)Id)\"\\s*:\\s*(\\d{16,})/g,\n '\"$1\":\"$2\"'\n );\n return JSON.parse(safe) as T;\n}\n\nexport async function listBoards(\n count = 20,\n cursor?: string,\n profile = \"default\"\n): Promise<BoardListResult> {\n const params = new URLSearchParams();\n params.set(\"count\", String(count));\n if (cursor) params.set(\"cursor\", cursor);\n\n const url = `${BASE_URL}/boards?${params.toString()}`;\n\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] GET ${url}`);\n }\n\n const res = await authedFetch(url, { method: \"GET\" }, profile);\n if (!res.ok) return handleError(res);\n\n const text = await res.text();\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] Response: ${text}`);\n }\n\n const data = safeParseJson<BoardListResult>(text);\n return { boards: data.boards ?? [], responseMetaData: data.responseMetaData };\n}\n\nexport async function listPosts(\n boardId: string,\n count = 20,\n cursor?: string,\n profile = \"default\"\n): Promise<PostListResult> {\n const params = new URLSearchParams();\n params.set(\"count\", String(count));\n if (cursor) params.set(\"cursor\", cursor);\n\n const url = `${BASE_URL}/boards/${boardId}/posts?${params.toString()}`;\n\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] GET ${url}`);\n }\n\n const res = await authedFetch(url, { method: \"GET\" }, profile);\n if (!res.ok) return handleError(res);\n\n const text = await res.text();\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] Response: ${text}`);\n }\n\n const data = safeParseJson<PostListResult>(text);\n return { posts: data.posts ?? [], responseMetaData: data.responseMetaData };\n}\n\nexport async function readPost(\n boardId: string,\n postId: string,\n profile = \"default\"\n): Promise<Post> {\n const url = `${BASE_URL}/boards/${boardId}/posts/${postId}`;\n\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] GET ${url}`);\n }\n\n const res = await authedFetch(url, { method: \"GET\" }, profile);\n if (!res.ok) return handleError(res);\n\n const text = await res.text();\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] Response: ${text}`);\n }\n\n return safeParseJson<Post>(text);\n}\n\nexport async function createPost(opts: CreatePostOptions): Promise<Post> {\n const profile = opts.profile ?? \"default\";\n\n const body: Record<string, unknown> = {\n title: opts.title,\n body: opts.body ?? \"\",\n };\n if (opts.enableComment !== undefined) body.enableComment = opts.enableComment;\n if (opts.sendNotifications !== undefined) body.sendNotifications = opts.sendNotifications;\n\n const url = `${BASE_URL}/boards/${opts.boardId}/posts`;\n\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] POST ${url}`);\n console.error(`[nworks] Body: ${JSON.stringify(body, null, 2)}`);\n }\n\n const res = await authedFetch(\n url,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n },\n profile\n );\n\n if (res.status === 201 || res.ok) {\n const text = await res.text();\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\n console.error(`[nworks] Response: ${text}`);\n }\n return safeParseJson<Post>(text);\n }\n return handleError(res);\n}\n","import { Command } from \"commander\";\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { loadCredentials, loadToken, loadUserToken, hasServiceAccountCreds } from \"../auth/config.js\";\nimport { output } from \"../output/format.js\";\nimport { cliError } from \"../output/cli-error.js\";\n\ninterface CheckResult {\n check: string;\n status: string;\n detail: string;\n}\n\nasync function runChecks(profile: string): Promise<CheckResult[]> {\n const results: CheckResult[] = [];\n\n // 1. Credentials\n let creds;\n try {\n creds = await loadCredentials(profile);\n results.push({ check: \"credentials\", status: \"OK\", detail: `clientId: ${creds.clientId}` });\n } catch {\n results.push({ check: \"credentials\", status: \"FAIL\", detail: \"인증 정보 없음. `nworks login` 또는 nworks_setup 필요\" });\n return results;\n }\n\n // 2. Service Account\n if (hasServiceAccountCreds(creds)) {\n results.push({ check: \"serviceAccount\", status: \"OK\", detail: creds.serviceAccount });\n } else {\n results.push({ check: \"serviceAccount\", status: \"SKIP\", detail: \"미설정 (봇 메시지 사용 시 필요)\" });\n }\n\n // 3. Private Key file\n if (creds.privateKeyPath) {\n if (existsSync(creds.privateKeyPath)) {\n try {\n await readFile(creds.privateKeyPath, \"utf-8\");\n results.push({ check: \"privateKey\", status: \"OK\", detail: creds.privateKeyPath });\n } catch {\n results.push({ check: \"privateKey\", status: \"FAIL\", detail: `읽기 불가: ${creds.privateKeyPath}` });\n }\n } else {\n results.push({ check: \"privateKey\", status: \"FAIL\", detail: `파일 없음: ${creds.privateKeyPath}` });\n }\n } else {\n results.push({ check: \"privateKey\", status: \"SKIP\", detail: \"미설정\" });\n }\n\n // 4. Bot ID\n if (creds.botId) {\n results.push({ check: \"botId\", status: \"OK\", detail: creds.botId });\n } else {\n results.push({ check: \"botId\", status: \"SKIP\", detail: \"미설정 (메시지 전송 시 필요)\" });\n }\n\n // 5. Service Account Token\n const token = await loadToken(profile);\n if (token) {\n const valid = token.expiresAt > Date.now() / 1000;\n results.push({\n check: \"serviceToken\",\n status: valid ? \"OK\" : \"EXPIRED\",\n detail: valid\n ? `만료: ${new Date(token.expiresAt * 1000).toISOString()}`\n : `만료됨: ${new Date(token.expiresAt * 1000).toISOString()}`,\n });\n } else {\n results.push({ check: \"serviceToken\", status: \"SKIP\", detail: \"토큰 없음\" });\n }\n\n // 6. User OAuth Token\n const userToken = await loadUserToken(profile);\n if (userToken) {\n const valid = userToken.expiresAt > Date.now() / 1000;\n results.push({\n check: \"userOAuth\",\n status: valid ? \"OK\" : \"EXPIRED\",\n detail: valid\n ? `scope: ${userToken.scope} | 만료: ${new Date(userToken.expiresAt * 1000).toISOString()}`\n : `만료됨 | scope: ${userToken.scope}`,\n });\n } else {\n results.push({ check: \"userOAuth\", status: \"SKIP\", detail: \"토큰 없음. `nworks login --user` 필요\" });\n }\n\n // 7. API connectivity test\n if (hasServiceAccountCreds(creds) && token && token.expiresAt > Date.now() / 1000) {\n try {\n const res = await fetch(\"https://www.worksapis.com/v1.0/users/me\", {\n headers: { Authorization: `Bearer ${token.accessToken}` },\n });\n if (res.ok) {\n results.push({ check: \"apiConnection\", status: \"OK\", detail: \"NAVER WORKS API 연결 성공\" });\n } else {\n results.push({ check: \"apiConnection\", status: \"FAIL\", detail: `HTTP ${res.status}` });\n }\n } catch (e) {\n results.push({ check: \"apiConnection\", status: \"FAIL\", detail: `연결 실패: ${(e as Error).message}` });\n }\n } else if (userToken && userToken.expiresAt > Date.now() / 1000) {\n try {\n const res = await fetch(\"https://www.worksapis.com/v1.0/users/me\", {\n headers: { Authorization: `Bearer ${userToken.accessToken}` },\n });\n if (res.ok) {\n results.push({ check: \"apiConnection\", status: \"OK\", detail: \"NAVER WORKS API 연결 성공\" });\n } else {\n results.push({ check: \"apiConnection\", status: \"FAIL\", detail: `HTTP ${res.status}` });\n }\n } catch (e) {\n results.push({ check: \"apiConnection\", status: \"FAIL\", detail: `연결 실패: ${(e as Error).message}` });\n }\n } else {\n results.push({ check: \"apiConnection\", status: \"SKIP\", detail: \"유효한 토큰 없음 — API 테스트 건너뜀\" });\n }\n\n return results;\n}\n\nexport { runChecks };\n\nexport const doctorCommand = new Command(\"doctor\")\n .description(\"Check nworks configuration and connectivity\")\n .option(\"--profile <name>\", \"Profile name\", \"default\")\n .option(\"--json\", \"JSON output\")\n .action(async (opts) => {\n try {\n const results = await runChecks(opts.profile as string);\n\n if (opts.json || !process.stdout.isTTY) {\n output(results, opts);\n } else {\n console.log(\"\\n nworks doctor\\n\");\n for (const r of results) {\n const icon = r.status === \"OK\" ? \"\\u2705\" : r.status === \"SKIP\" ? \"\\u2796\" : \"\\u274C\";\n console.log(` ${icon} ${r.check.padEnd(16)} ${r.detail}`);\n }\n console.log();\n }\n } catch (err) {\n cliError(err, opts);\n }\n });\n","interface FormatOptions {\n json?: boolean;\n}\n\nexport function output(data: unknown, opts: FormatOptions = {}): void {\n const useJson = opts.json || !process.stdout.isTTY;\n\n if (useJson) {\n console.log(JSON.stringify(data, null, 2));\n return;\n }\n\n if (Array.isArray(data)) {\n printTable(data);\n } else if (typeof data === \"object\" && data !== null) {\n const record = data as Record<string, unknown>;\n for (const value of Object.values(record)) {\n if (Array.isArray(value) && value.length > 0) {\n printTable(value);\n return;\n }\n }\n for (const [key, value] of Object.entries(record)) {\n console.log(` ${key}: ${String(value)}`);\n }\n } else {\n console.log(String(data));\n }\n}\n\nfunction printTable(rows: unknown[]): void {\n if (rows.length === 0) {\n console.log(\" (no data)\");\n return;\n }\n\n const first = rows[0] as Record<string, unknown>;\n const keys = Object.keys(first);\n\n const widths: Record<string, number> = {};\n for (const key of keys) {\n widths[key] = key.length;\n }\n for (const row of rows) {\n const record = row as Record<string, unknown>;\n for (const key of keys) {\n const len = String(record[key] ?? \"\").length;\n if (len > (widths[key] ?? 0)) {\n widths[key] = len;\n }\n }\n }\n\n const header = keys.map((k) => k.padEnd(widths[k] ?? 0)).join(\" \");\n const separator = keys.map((k) => \"─\".repeat(widths[k] ?? 0)).join(\"──\");\n\n console.log(` ${header}`);\n console.log(` ${separator}`);\n\n for (const row of rows) {\n const record = row as Record<string, unknown>;\n const line = keys\n .map((k) => String(record[k] ?? \"\").padEnd(widths[k] ?? 0))\n .join(\" \");\n console.log(` ${line}`);\n }\n}\n\nexport function errorOutput(\n error: { code?: string; message: string; hint?: string },\n opts: FormatOptions = {}\n): void {\n const payload = {\n success: false,\n error: { code: error.code ?? \"ERROR\", message: error.message, hint: error.hint },\n };\n\n if (opts.json || !process.stderr.isTTY) {\n console.error(JSON.stringify(payload, null, 2));\n } else {\n console.error(` Error: ${error.message}`);\n if (error.code) {\n console.error(` Code: ${error.code}`);\n }\n if (error.hint) {\n console.error(` → ${error.hint}`);\n }\n }\n}\n","import { ApiError, AuthError } from \"./error.js\";\n\n/** Scope required by each command/API area */\nexport const REQUIRED_SCOPES: Record<string, string> = {\n calendar: \"calendar\",\n \"calendar.list\": \"calendar.read\",\n \"calendar.create\": \"calendar calendar.read\",\n \"calendar.update\": \"calendar calendar.read\",\n \"calendar.delete\": \"calendar calendar.read\",\n mail: \"mail\",\n \"mail.send\": \"mail\",\n \"mail.list\": \"mail.read\",\n \"mail.read\": \"mail.read\",\n task: \"task\",\n \"task.list\": \"task.read\",\n \"task.create\": \"task user.read\",\n \"task.update\": \"task user.read\",\n \"task.delete\": \"task user.read\",\n drive: \"file\",\n \"drive.list\": \"file.read\",\n \"drive.upload\": \"file\",\n \"drive.download\": \"file.read\",\n board: \"board\",\n \"board.list\": \"board.read\",\n \"board.posts\": \"board.read\",\n \"board.read\": \"board.read\",\n \"board.create\": \"board\",\n};\n\nconst ERROR_HINTS_CLI: Record<string, string> = {\n FORBIDDEN: \"권한이 부족합니다. Developer Console에서 OAuth Scope를 확인하세요.\",\n ACCESS_DENIED: \"접근이 거부됐습니다. Admin에서 Bot을 추가했는지 확인하세요.\",\n SERVICE_ACCOUNT_NOT_ALLOWED:\n \"서비스 계정으로는 이 API를 사용할 수 없습니다. `nworks login --user`로 User OAuth 로그인하세요.\",\n UNAUTHORIZED: \"인증이 만료됐습니다. `nworks login`으로 다시 로그인하세요.\",\n};\n\nconst ERROR_HINTS_MCP: Record<string, string> = {\n FORBIDDEN: \"권한이 부족합니다. Developer Console에서 OAuth Scope를 확인하세요.\",\n ACCESS_DENIED: \"접근이 거부됐습니다. Admin에서 Bot을 추가했는지 확인하세요.\",\n SERVICE_ACCOUNT_NOT_ALLOWED:\n \"서비스 계정으로는 이 API를 사용할 수 없습니다. nworks_login_user tool로 User OAuth 로그인을 먼저 해주세요.\",\n UNAUTHORIZED: \"인증이 만료됐습니다. nworks_setup tool로 재설정하세요.\",\n};\n\n/**\n * Build a user-friendly hint string for CLI error output.\n * @param err The thrown error\n * @param area Optional command area (e.g. \"calendar.list\") to suggest the exact scope\n */\nexport function cliErrorHint(err: unknown, area?: string): string {\n if (err instanceof ApiError) {\n const hint = ERROR_HINTS_CLI[err.code];\n const scopeHint = area ? buildScopeHint(area, \"cli\") : \"\";\n if (hint) {\n return `[${err.code}] ${err.message}\\n → ${hint}${scopeHint}`;\n }\n return `[${err.code}] ${err.message}${scopeHint}`;\n }\n if (err instanceof AuthError) {\n return `${err.message}\\n → ${ERROR_HINTS_CLI[\"UNAUTHORIZED\"]}`;\n }\n return (err as Error).message;\n}\n\n/**\n * Build a user-friendly hint string for MCP tool error output.\n */\nexport function mcpErrorHint(err: unknown, area?: string): string {\n if (err instanceof ApiError) {\n const hint = ERROR_HINTS_MCP[err.code];\n const scopeHint = area ? buildScopeHint(area, \"mcp\") : \"\";\n if (hint) {\n return `Error: [${err.code}] ${err.message}\\n\\n[안내] ${hint}${scopeHint}`;\n }\n return `Error: [${err.code}] ${err.message}${scopeHint}`;\n }\n if (err instanceof AuthError) {\n return `Error: ${err.message}\\n\\n[안내] 인증 정보가 없습니다. nworks_setup tool로 Client ID/Secret을 먼저 설정해주세요.`;\n }\n return `Error: ${(err as Error).message}`;\n}\n\nfunction buildScopeHint(area: string, mode: \"cli\" | \"mcp\"): string {\n const scope = REQUIRED_SCOPES[area];\n if (!scope) return \"\";\n const scopes = scope.split(\" \").join(\", \");\n if (mode === \"cli\") {\n return `\\n → 이 명령어는 ${scopes} scope가 필요합니다. \\`nworks login --user --scope \"${scope}\"\\`를 실행하세요.`;\n }\n return `\\n → 이 API는 ${scopes} scope가 필요합니다. nworks_login_user tool로 로그인하세요 (scope를 지정하지 않으면 전체 권한이 자동 포함됩니다).`;\n}\n","import { ApiError, AuthError } from \"../utils/error.js\";\nimport { cliErrorHint } from \"../utils/error-hints.js\";\nimport { errorOutput } from \"./format.js\";\n\n/**\n * Standard CLI error handler with Korean hints.\n * Use in command catch blocks: `cliError(err, opts, \"calendar.list\")`\n */\nexport function cliError(\n err: unknown,\n opts: { json?: boolean } = {},\n area?: string,\n): void {\n const error = err as Error;\n\n if (error instanceof ApiError) {\n errorOutput(\n {\n code: error.code,\n message: error.message,\n hint: cliErrorHint(err, area).split(\"\\n\").slice(1).map((l) => l.replace(/^\\s+→\\s*/, \"\")).join(\" \"),\n },\n opts,\n );\n } else if (error instanceof AuthError) {\n errorOutput(\n {\n code: \"AUTH_ERROR\",\n message: error.message,\n hint: \"인증이 만료됐습니다. `nworks login`으로 다시 로그인하세요.\",\n },\n opts,\n );\n } else {\n errorOutput({ message: error.message }, opts);\n }\n\n process.exitCode = 1;\n}\n","import { startMcpServer } from \"./mcp/server.js\";\n\nstartMcpServer().catch((err) => {\n console.error(\"MCP server failed:\", err);\n process.exit(1);\n});\n"],"mappings":"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","names":["readFile","readFile","AUTH_URL","refreshToken","BASE_URL","readFile","BASE_URL","authedFetch","handleError","readFile","BASE_URL","authedFetch","handleError","BASE_URL","authedFetch","handleError","BASE_URL","authedFetch","handleError","BASE_URL","authedFetch","handleError","BASE_URL","authedFetch","handleError","existsSync","readFile","existsSync","readFile","writeFile","join"]}
1
+ {"version":3,"sources":["../src/mcp/server.ts","../src/mcp/tools.ts","../src/utils/error.ts","../src/auth/config.ts","../src/auth/jwt.ts","../src/auth/token.ts","../src/api/client.ts","../src/api/message.ts","../src/api/directory.ts","../src/api/calendar.ts","../src/auth/oauth-user.ts","../src/auth/token-user.ts","../src/api/drive.ts","../src/api/mail.ts","../src/api/task.ts","../src/api/board.ts","../src/commands/doctor.ts","../src/output/format.ts","../src/utils/error-hints.ts","../src/output/cli-error.ts","../src/mcp.ts"],"sourcesContent":["import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\r\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\r\nimport { registerTools } from \"./tools.js\";\r\nimport { loadCredentials, loadUserToken } from \"../auth/config.js\";\r\n\r\nexport async function startMcpServer(): Promise<void> {\r\n // 인증 상태 확인 (경고만, 서버는 항상 시작)\r\n try {\r\n await loadCredentials();\r\n } catch {\r\n console.error(\r\n \"[nworks] Authentication required. Run: nworks login\"\r\n );\r\n }\r\n\r\n try {\r\n const userToken = await loadUserToken();\r\n if (!userToken) {\r\n console.error(\r\n \"[nworks] User OAuth not configured. Run: nworks login --user\"\r\n );\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n\r\n const server = new McpServer({\r\n name: \"nworks\",\r\n version: \"1.0.0\",\r\n });\r\n\r\n registerTools(server);\r\n\r\n const transport = new StdioServerTransport();\r\n await server.connect(transport);\r\n}\r\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\r\nimport { z } from \"zod\";\r\nimport * as messageApi from \"../api/message.js\";\r\nimport * as directoryApi from \"../api/directory.js\";\r\nimport * as calendarApi from \"../api/calendar.js\";\r\nimport * as driveApi from \"../api/drive.js\";\r\nimport * as mailApi from \"../api/mail.js\";\r\nimport * as taskApi from \"../api/task.js\";\r\nimport * as boardApi from \"../api/board.js\";\r\nimport { clearCredentials, loadCredentials, loadToken, loadUserToken, saveCredentials, saveUserToken } from \"../auth/config.js\";\r\nimport { runChecks } from \"../commands/doctor.js\";\r\nimport { buildAuthorizeUrl, startOAuthCallbackServer } from \"../auth/oauth-user.js\";\r\nimport { mcpErrorHint } from \"../utils/error-hints.js\";\r\n\r\nexport function registerTools(server: McpServer): void {\r\n // Tool 0: 초기 설정\r\n server.tool(\r\n \"nworks_setup\",\r\n \"NAVER WORKS API 인증 정보를 설정합니다. 민감 정보(Client Secret, Private Key 경로)는 이 tool의 파라미터로 받지 않습니다 — 사용자가 MCP 설정 파일(예: claude_desktop_config.json)의 env 필드에 NWORKS_CLIENT_SECRET(필수)과 NWORKS_PRIVATE_KEY_PATH(Service Account 사용 시)를 미리 설정해야 합니다. Developer Console: https://dev.worksmobile.com. 환경변수가 설정되지 않은 경우, 사용자에게 설정 방법을 안내하세요. 메시지/구성원조회는 Service Account 인증(serviceAccount, botId + 환경변수 NWORKS_PRIVATE_KEY_PATH 필요). 캘린더/메일/할일/드라이브/게시판은 User OAuth 인증(설정 후 nworks_login_user로 브라우저 로그인 필요). OAuth Redirect URI: http://localhost:9876/callback\",\r\n {\r\n clientId: z.string().describe(\"Client ID (Developer Console에서 발급)\"),\r\n serviceAccount: z.string().optional().describe(\"Service Account ID (예: xxxxx.serviceaccount@domain)\"),\r\n botId: z.string().optional().describe(\"Bot ID (메시지 전송 시 필요)\"),\r\n domainId: z.string().optional().describe(\"Domain ID\"),\r\n },\r\n async ({ clientId, serviceAccount, botId, domainId }) => {\r\n try {\r\n const resolvedSecret = process.env[\"NWORKS_CLIENT_SECRET\"];\r\n if (!resolvedSecret) {\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify({\r\n error: true,\r\n message: \"환경변수 NWORKS_CLIENT_SECRET이 설정되어 있지 않습니다.\",\r\n solution: \"사용자에게 다음 안내를 전달하세요: MCP 설정 파일(예: claude_desktop_config.json)의 nworks 서버 설정에 env 필드를 추가해야 합니다.\",\r\n example: {\r\n mcpServers: {\r\n nworks: {\r\n command: \"npx\",\r\n args: [\"-y\", \"nworks\", \"mcp\"],\r\n env: {\r\n NWORKS_CLIENT_SECRET: \"<Developer Console에서 발급받은 Client Secret>\",\r\n },\r\n },\r\n },\r\n },\r\n developerConsole: \"https://dev.worksmobile.com\",\r\n }) }],\r\n isError: true,\r\n };\r\n }\r\n\r\n const resolvedPrivateKeyPath = process.env[\"NWORKS_PRIVATE_KEY_PATH\"];\r\n\r\n await saveCredentials({\r\n clientId,\r\n clientSecret: resolvedSecret,\r\n serviceAccount,\r\n privateKeyPath: resolvedPrivateKeyPath,\r\n botId,\r\n domainId,\r\n });\r\n\r\n const nextSteps: string[] = [];\r\n if (serviceAccount && resolvedPrivateKeyPath && botId) {\r\n nextSteps.push(\"Service Account 인증 준비 완료 — 봇 메시지 등 바로 사용 가능\");\r\n } else if (serviceAccount && botId && !resolvedPrivateKeyPath) {\r\n nextSteps.push(\"NWORKS_PRIVATE_KEY_PATH 환경변수가 설정되지 않았습니다. Service Account 인증에는 Private Key 경로가 필요합니다. 사용자에게 MCP 설정 파일(예: claude_desktop_config.json)의 env 필드에 NWORKS_PRIVATE_KEY_PATH를 추가하도록 안내하세요. Private Key는 Developer Console(https://dev.worksmobile.com)에서 다운로드할 수 있습니다.\");\r\n }\r\n nextSteps.push(\"User OAuth가 필요한 API는 nworks_login_user tool로 브라우저 로그인을 진행하세요\");\r\n\r\n const mask = (s: string) => s.length <= 4 ? \"****\" : `****${s.slice(-Math.min(4, Math.floor(s.length / 3)))}`;\r\n\r\n return {\r\n content: [\r\n {\r\n type: \"text\" as const,\r\n text: JSON.stringify({\r\n success: true,\r\n message: \"인증 정보가 저장되었습니다.\",\r\n nextSteps,\r\n clientId,\r\n clientSecret: `${mask(resolvedSecret)} (환경변수)`,\r\n serviceAccount: serviceAccount ?? null,\r\n privateKeyPath: resolvedPrivateKeyPath ? `${mask(resolvedPrivateKeyPath)} (환경변수)` : null,\r\n botId: botId ?? null,\r\n }),\r\n },\r\n ],\r\n };\r\n } catch (err) {\r\n return {\r\n content: [{ type: \"text\" as const, text: mcpErrorHint(err) }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n\r\n // Tool 1: 메시지 전송\r\n server.tool(\r\n \"nworks_message_send\",\r\n \"NAVER WORKS 메시지를 전송합니다 (봇이 사용자 또는 채널에 발송). Service Account 인증 사용 (nworks_setup에서 serviceAccount, botId 설정 + 환경변수 NWORKS_PRIVATE_KEY_PATH 필요. User OAuth 불필요)\",\r\n {\r\n to: z.string().optional().describe(\"수신자 userId (channel과 택 1). nworks_directory_members로 userId 조회 가능\"),\r\n channel: z.string().optional().describe(\"채널 channelId (to와 택 1). nworks_message_members로 채널 구성원 확인 가능\"),\r\n text: z.string().describe(\"메시지 본문\"),\r\n type: z\r\n .enum([\"text\", \"button\", \"list\"])\r\n .optional()\r\n .describe(\"메시지 타입 (기본: text)\"),\r\n actions: z\r\n .string()\r\n .optional()\r\n .describe(\"버튼 액션 JSON (type=button일 때)\"),\r\n elements: z\r\n .string()\r\n .optional()\r\n .describe(\"리스트 항목 JSON (type=list일 때)\"),\r\n },\r\n async ({ to, channel, text, type, actions, elements }) => {\r\n try {\r\n const result = await messageApi.send({\r\n to,\r\n channel,\r\n text,\r\n type,\r\n actions,\r\n elements,\r\n });\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify(result) }],\r\n };\r\n } catch (err) {\r\n return {\r\n content: [{ type: \"text\" as const, text: mcpErrorHint(err) }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n\r\n // Tool 2: 채널 구성원\r\n server.tool(\r\n \"nworks_message_members\",\r\n \"특정 채널의 구성원 목록을 조회합니다. '이 채널에 누가 있어?' 등의 요청에 사용. Service Account 인증 사용 (nworks_setup 필요)\",\r\n {\r\n channel: z.string().describe(\"채널 channelId\"),\r\n },\r\n async ({ channel }) => {\r\n try {\r\n const result = await messageApi.listMembers(channel);\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify(result) }],\r\n };\r\n } catch (err) {\r\n return {\r\n content: [{ type: \"text\" as const, text: mcpErrorHint(err) }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n\r\n // Tool 3: 조직 구성원 목록\r\n server.tool(\r\n \"nworks_directory_members\",\r\n \"NAVER WORKS 조직 구성원(직원) 목록을 조회합니다. '구성원 목록 보여줘', '팀원 찾아줘', '누구한테 메시지 보낼지 userId 찾기' 등에 사용. Service Account 인증 사용 (nworks_setup 필요). 메시지 전송 시 수신자 userId를 여기서 조회 가능\",\r\n {},\r\n async () => {\r\n try {\r\n const result = await directoryApi.listUsers();\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify(result) }],\r\n };\r\n } catch (err) {\r\n return {\r\n content: [{ type: \"text\" as const, text: mcpErrorHint(err) }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n\r\n // Tool 4: 캘린더 일정 목록\r\n server.tool(\r\n \"nworks_calendar_list\",\r\n \"사용자의 캘린더 일정/스케줄을 조회합니다. '오늘 일정 알려줘', '이번 주 스케줄 확인' 등의 요청에 사용. User OAuth 인증 필요 (calendar.read scope). 미로그인 시 nworks_login_user로 로그인 필요\",\r\n {\r\n fromDateTime: z.string().describe(\"시작 일시 (YYYY-MM-DDThh:mm:ss+09:00)\"),\r\n untilDateTime: z.string().describe(\"종료 일시 (YYYY-MM-DDThh:mm:ss+09:00)\"),\r\n userId: z.string().optional().describe(\"대상 사용자 ID (미지정 시 me)\"),\r\n },\r\n async ({ fromDateTime, untilDateTime, userId }) => {\r\n try {\r\n const result = await calendarApi.listEvents(\r\n fromDateTime,\r\n untilDateTime,\r\n userId ?? \"me\"\r\n );\r\n const events = result.events.flatMap((e) =>\r\n e.eventComponents.map((c) => ({\r\n eventId: c.eventId,\r\n summary: c.summary,\r\n start: c.start.dateTime ?? c.start.date ?? \"\",\r\n end: c.end.dateTime ?? c.end.date ?? \"\",\r\n location: c.location ?? \"\",\r\n }))\r\n );\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify({ events, count: events.length }) }],\r\n };\r\n } catch (err) {\r\n return {\r\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"calendar.list\") }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n\r\n // Tool 5: 캘린더 일정 생성\r\n server.tool(\r\n \"nworks_calendar_create\",\r\n \"캘린더 일정을 새로 만듭니다. '회의 잡아줘', '일정 등록해줘' 등의 요청에 사용. User OAuth 인증 필요 (calendar + calendar.read scope)\",\r\n {\r\n summary: z.string().describe(\"일정 제목\"),\r\n start: z.string().describe(\"시작 일시 (YYYY-MM-DDThh:mm:ss)\"),\r\n end: z.string().describe(\"종료 일시 (YYYY-MM-DDThh:mm:ss)\"),\r\n timeZone: z.string().optional().describe(\"타임존 (기본: Asia/Seoul)\"),\r\n description: z.string().optional().describe(\"일정 설명\"),\r\n location: z.string().optional().describe(\"장소\"),\r\n attendees: z.array(z.object({ email: z.string(), displayName: z.string().optional() })).optional().describe(\"참석자 목록\"),\r\n sendNotification: z.boolean().optional().describe(\"참석자에게 알림 발송 (기본: false)\"),\r\n userId: z.string().optional().describe(\"대상 사용자 ID (미지정 시 me)\"),\r\n },\r\n async ({ summary, start, end, timeZone, description, location, attendees, sendNotification, userId }) => {\r\n try {\r\n const result = await calendarApi.createEvent({\r\n summary,\r\n start,\r\n end,\r\n timeZone,\r\n description,\r\n location,\r\n attendees,\r\n sendNotification,\r\n userId: userId ?? \"me\",\r\n });\r\n const event = result.eventComponents?.[0];\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify({ success: true, eventId: event?.eventId, summary: event?.summary, start: event?.start, end: event?.end }) }],\r\n };\r\n } catch (err) {\r\n return {\r\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"calendar.create\") }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n\r\n // Tool 6: 캘린더 일정 수정\r\n server.tool(\r\n \"nworks_calendar_update\",\r\n \"기존 캘린더 일정을 수정합니다. '일정 시간 변경해줘', '회의 제목 바꿔줘' 등의 요청에 사용. User OAuth 인증 필요 (calendar + calendar.read scope). eventId는 nworks_calendar_list로 조회 가능\",\r\n {\r\n eventId: z.string().describe(\"일정 ID (nworks_calendar_list로 조회 가능)\"),\r\n summary: z.string().optional().describe(\"새 제목\"),\r\n start: z.string().optional().describe(\"새 시작 일시 (YYYY-MM-DDThh:mm:ss)\"),\r\n end: z.string().optional().describe(\"새 종료 일시 (YYYY-MM-DDThh:mm:ss)\"),\r\n timeZone: z.string().optional().describe(\"타임존 (기본: Asia/Seoul)\"),\r\n description: z.string().optional().describe(\"새 설명\"),\r\n location: z.string().optional().describe(\"새 장소\"),\r\n sendNotification: z.boolean().optional().describe(\"참석자에게 알림 발송 (기본: false)\"),\r\n userId: z.string().optional().describe(\"대상 사용자 ID (미지정 시 me)\"),\r\n },\r\n async ({ eventId, summary, start, end, timeZone, description, location, sendNotification, userId }) => {\r\n try {\r\n await calendarApi.updateEvent({\r\n eventId,\r\n summary,\r\n start,\r\n end,\r\n timeZone,\r\n description,\r\n location,\r\n sendNotification,\r\n userId: userId ?? \"me\",\r\n });\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify({ success: true, eventId, message: \"일정이 수정되었습니다\" }) }],\r\n };\r\n } catch (err) {\r\n return {\r\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"calendar.update\") }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n\r\n // Tool 7: 캘린더 일정 삭제\r\n server.tool(\r\n \"nworks_calendar_delete\",\r\n \"캘린더 일정을 삭제합니다. '일정 취소해줘' 등의 요청에 사용. User OAuth 인증 필요 (calendar + calendar.read scope). eventId는 nworks_calendar_list로 조회 가능\",\r\n {\r\n eventId: z.string().describe(\"삭제할 일정 ID (nworks_calendar_list로 조회 가능)\"),\r\n sendNotification: z.boolean().optional().describe(\"참석자에게 알림 발송 (기본: false)\"),\r\n userId: z.string().optional().describe(\"대상 사용자 ID (미지정 시 me)\"),\r\n },\r\n async ({ eventId, sendNotification, userId }) => {\r\n try {\r\n await calendarApi.deleteEvent(\r\n eventId,\r\n userId ?? \"me\",\r\n sendNotification ?? false\r\n );\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify({ success: true, eventId, message: \"일정이 삭제되었습니다\" }) }],\r\n };\r\n } catch (err) {\r\n return {\r\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"calendar.delete\") }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n\r\n // Tool 8: 드라이브 파일 목록\r\n server.tool(\r\n \"nworks_drive_list\",\r\n \"NAVER WORKS 드라이브의 파일/폴더 목록을 조회합니다. '드라이브 파일 보여줘', '내 파일 목록' 등의 요청에 사용. User OAuth 인증 필요 (file.read scope)\",\r\n {\r\n userId: z.string().optional().describe(\"대상 사용자 ID (미지정 시 me)\"),\r\n folderId: z.string().optional().describe(\"폴더 ID (미지정 시 루트)\"),\r\n count: z.number().optional().describe(\"페이지당 항목 수 (기본: 20, 최대: 200)\"),\r\n cursor: z.string().optional().describe(\"페이지네이션 커서\"),\r\n },\r\n async ({ userId, folderId, count, cursor }) => {\r\n try {\r\n const result = await driveApi.listFiles(\r\n userId ?? \"me\",\r\n folderId,\r\n count ?? 20,\r\n cursor\r\n );\r\n const files = result.files.map((f) => ({\r\n fileId: f.fileId,\r\n name: f.fileName,\r\n type: f.fileType,\r\n size: f.fileSize,\r\n modified: f.modifiedTime,\r\n path: f.filePath,\r\n }));\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify({ files, count: files.length, hasMore: !!result.responseMetaData?.nextCursor, nextCursor: result.responseMetaData?.nextCursor ?? null }) }],\r\n };\r\n } catch (err) {\r\n return {\r\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"drive.list\") }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n\r\n // Tool 9: 드라이브 파일 업로드\r\n server.tool(\r\n \"nworks_drive_upload\",\r\n \"파일을 드라이브에 업로드합니다 (User OAuth file scope 필요). content(base64)와 fileName으로 전달하거나, filePath로 로컬 파일 경로를 지정합니다. MCP 클라이언트에서는 content+fileName 방식을 권장합니다.\",\r\n {\r\n content: z.string().optional().describe(\"업로드할 파일 내용 (base64 인코딩). filePath 대신 사용\"),\r\n fileName: z.string().optional().describe(\"파일명 (content 사용 시 필수)\"),\r\n filePath: z.string().optional().describe(\"업로드할 로컬 파일 경로 (content 대신 사용, 로컬 환경에서만 동작)\"),\r\n userId: z.string().optional().describe(\"대상 사용자 ID (미지정 시 me)\"),\r\n folderId: z.string().optional().describe(\"업로드할 폴더 ID (미지정 시 루트)\"),\r\n overwrite: z.boolean().optional().describe(\"동일 파일명 덮어쓰기 (기본: false)\"),\r\n },\r\n async ({ content, fileName, filePath, userId, folderId, overwrite }) => {\r\n try {\r\n let result: driveApi.UploadResult;\r\n\r\n if (content && fileName) {\r\n // MCP 방식: base64 content를 직접 받아서 업로드\r\n const buffer = Buffer.from(content, \"base64\");\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] MCP upload: fileName=${fileName}, bufferSize=${buffer.length}`);\r\n }\r\n result = await driveApi.uploadBuffer(\r\n buffer,\r\n fileName,\r\n userId ?? \"me\",\r\n folderId,\r\n overwrite ?? false\r\n );\r\n } else if (filePath) {\r\n // 로컬 파일 경로 방식\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] MCP upload: filePath=${filePath}`);\r\n }\r\n result = await driveApi.uploadFile(\r\n filePath,\r\n userId ?? \"me\",\r\n folderId,\r\n overwrite ?? false\r\n );\r\n } else {\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify({ error: true, message: \"content+fileName 또는 filePath 중 하나를 지정해야 합니다. MCP 클라이언트에서는 파일 내용을 base64로 인코딩하여 content 파라미터에 전달하고, fileName에 파일명을 지정하세요.\" }) }],\r\n isError: true,\r\n };\r\n }\r\n\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify({ success: true, ...result }) }],\r\n };\r\n } catch (err) {\r\n const error = err as Error;\r\n const detail = process.env[\"NWORKS_VERBOSE\"] === \"1\"\r\n ? ` | stack: ${error.stack}`\r\n : \"\";\r\n return {\r\n content: [{ type: \"text\" as const, text: `${mcpErrorHint(err, \"drive.upload\")}${detail}` }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n\r\n // Tool 10: 드라이브 파일 다운로드\r\n server.tool(\r\n \"nworks_drive_download\",\r\n \"드라이브 파일을 다운로드합니다. User OAuth 인증 필요 (file.read scope). outputDir을 지정하면 로컬에 파일로 저장하고, 미지정 시 파일 내용을 직접 반환합니다 (텍스트는 text, 바이너리는 base64). 5MB 초과 파일은 반드시 outputDir를 지정해야 합니다.\",\r\n {\r\n fileId: z.string().describe(\"다운로드할 파일 ID (nworks_drive_list로 조회 가능)\"),\r\n outputDir: z.string().optional().describe(\"저장 디렉토리 (지정 시 파일로 저장, 미지정 시 내용을 직접 반환)\"),\r\n outputName: z.string().optional().describe(\"저장 파일명 (미지정 시 원본 파일명)\"),\r\n userId: z.string().optional().describe(\"대상 사용자 ID (미지정 시 me)\"),\r\n },\r\n async ({ fileId, outputDir, outputName, userId }) => {\r\n try {\r\n const result = await driveApi.downloadFile(\r\n fileId,\r\n userId ?? \"me\"\r\n );\r\n\r\n const fileName = outputName ?? result.fileName ?? fileId;\r\n\r\n if (outputDir) {\r\n // 로컬 저장 방식 (CLI 환경용)\r\n const { writeFile } = await import(\"node:fs/promises\");\r\n const { join } = await import(\"node:path\");\r\n const outPath = join(outputDir, fileName);\r\n await writeFile(outPath, result.buffer);\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify({ success: true, fileName, path: outPath, size: result.buffer.length }) }],\r\n };\r\n }\r\n\r\n // 내용 직접 반환 방식 (MCP 환경용)\r\n const MAX_INLINE_SIZE = 5 * 1024 * 1024; // 5MB\r\n if (result.buffer.length > MAX_INLINE_SIZE) {\r\n const sizeMB = (result.buffer.length / (1024 * 1024)).toFixed(1);\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify({ error: true, message: `파일이 너무 큽니다 (${sizeMB}MB). outputDir를 지정해서 로컬에 저장하세요.`, fileName, size: result.buffer.length }) }],\r\n isError: true,\r\n };\r\n }\r\n\r\n const textExtensions = /\\.(txt|md|csv|json|xml|html|htm|css|js|ts|jsx|tsx|yaml|yml|toml|ini|cfg|conf|log|sh|bash|zsh|py|rb|java|go|rs|c|cpp|h|hpp|sql|graphql|env|gitignore|dockerignore|editorconfig)$/i;\r\n const isText = textExtensions.test(fileName);\r\n\r\n if (isText) {\r\n const text = result.buffer.toString(\"utf-8\");\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify({ success: true, fileName, size: result.buffer.length, encoding: \"text\", content: text }) }],\r\n };\r\n }\r\n\r\n const base64 = result.buffer.toString(\"base64\");\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify({ success: true, fileName, size: result.buffer.length, encoding: \"base64\", content: base64 }) }],\r\n };\r\n } catch (err) {\r\n return {\r\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"drive.download\") }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n\r\n // Tool 11: 메일 전송\r\n server.tool(\r\n \"nworks_mail_send\",\r\n \"NAVER WORKS 메일을 전송합니다. '메일 보내줘', '이메일 작성해줘' 등의 요청에 사용. 비동기 전송(성공 시 202). User OAuth 인증 필요 (mail scope)\",\r\n {\r\n to: z.string().describe(\"수신자 이메일 (여러 명은 ; 로 구분)\"),\r\n subject: z.string().describe(\"메일 제목\"),\r\n body: z.string().optional().describe(\"메일 본문\"),\r\n cc: z.string().optional().describe(\"참조 이메일 (여러 명은 ; 로 구분)\"),\r\n bcc: z.string().optional().describe(\"숨은참조 이메일 (여러 명은 ; 로 구분)\"),\r\n contentType: z.enum([\"html\", \"text\"]).optional().describe(\"본문 형식 (기본: html)\"),\r\n userId: z.string().optional().describe(\"발신자 ID (미지정 시 me)\"),\r\n },\r\n async ({ to, subject, body, cc, bcc, contentType, userId }) => {\r\n try {\r\n await mailApi.sendMail({\r\n to,\r\n subject,\r\n body,\r\n cc,\r\n bcc,\r\n contentType,\r\n userId: userId ?? \"me\",\r\n });\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify({ success: true, message: \"메일이 전송되었습니다 (비동기 처리)\" }) }],\r\n };\r\n } catch (err) {\r\n return {\r\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"mail.send\") }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n\r\n // Tool 12: 메일 목록 조회\r\n server.tool(\r\n \"nworks_mail_list\",\r\n \"받은 메일 목록을 조회합니다. '메일 확인해줘', '받은편지함 보여줘', '안 읽은 메일 있어?' 등의 요청에 사용. User OAuth 인증 필요 (mail.read scope)\",\r\n {\r\n folderId: z.number().optional().describe(\"메일 폴더 ID (기본: 0 = 받은편지함)\"),\r\n count: z.number().optional().describe(\"페이지당 항목 수 (기본: 30, 최대: 200)\"),\r\n cursor: z.string().optional().describe(\"페이지네이션 커서\"),\r\n isUnread: z.boolean().optional().describe(\"읽지 않은 메일만 조회\"),\r\n userId: z.string().optional().describe(\"대상 사용자 ID (미지정 시 me)\"),\r\n },\r\n async ({ folderId, count, cursor, isUnread, userId }) => {\r\n try {\r\n const result = await mailApi.listMails(\r\n folderId ?? 0,\r\n userId ?? \"me\",\r\n count ?? 30,\r\n cursor,\r\n isUnread\r\n );\r\n const mails = result.mails.map((m) => ({\r\n mailId: m.mailId,\r\n from: m.from.email,\r\n subject: m.subject,\r\n date: m.receivedTime,\r\n status: m.status,\r\n attachments: m.attachCount ?? 0,\r\n }));\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify({ mails, count: mails.length, totalCount: result.totalCount, unreadCount: result.unreadCount, hasMore: !!result.responseMetaData?.nextCursor, nextCursor: result.responseMetaData?.nextCursor ?? null }) }],\r\n };\r\n } catch (err) {\r\n return {\r\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"mail.list\") }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n\r\n // Tool 13: 메일 상세 조회\r\n server.tool(\r\n \"nworks_mail_read\",\r\n \"특정 메일의 상세 내용(본문, 첨부파일 등)을 조회합니다. '이 메일 내용 보여줘' 등의 요청에 사용. mailId는 nworks_mail_list로 조회 가능. User OAuth 인증 필요 (mail.read scope)\",\r\n {\r\n mailId: z.number().describe(\"메일 ID (nworks_mail_list로 조회 가능)\"),\r\n userId: z.string().optional().describe(\"대상 사용자 ID (미지정 시 me)\"),\r\n },\r\n async ({ mailId, userId }) => {\r\n try {\r\n const result = await mailApi.readMail(\r\n mailId,\r\n userId ?? \"me\"\r\n );\r\n const mail = result.mail;\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify({\r\n mailId: mail.mailId,\r\n from: mail.from,\r\n to: mail.to,\r\n cc: mail.cc ?? [],\r\n subject: mail.subject,\r\n body: mail.body,\r\n date: mail.receivedTime,\r\n attachments: result.attachments?.map((a) => ({\r\n id: a.attachmentId,\r\n filename: a.filename,\r\n contentType: a.contentType,\r\n size: a.size,\r\n })) ?? [],\r\n }) }],\r\n };\r\n } catch (err) {\r\n return {\r\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"mail.read\") }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n\r\n // Tool 14: 할 일 목록 조회\r\n server.tool(\r\n \"nworks_task_list\",\r\n \"할 일(TODO) 목록을 조회합니다. '할 일 확인해줘', 'TODO 목록 보여줘', '남은 업무 뭐 있어?' 등의 요청에 사용. User OAuth 인증 필요 (task.read scope)\",\r\n {\r\n categoryId: z.string().optional().describe(\"카테고리 ID (기본: default)\"),\r\n status: z.enum([\"TODO\", \"ALL\"]).optional().describe(\"필터: TODO 또는 ALL (기본: ALL)\"),\r\n count: z.number().optional().describe(\"페이지당 항목 수 (기본: 50, 최대: 100)\"),\r\n cursor: z.string().optional().describe(\"페이지네이션 커서\"),\r\n userId: z.string().optional().describe(\"대상 사용자 ID (미지정 시 me)\"),\r\n },\r\n async ({ categoryId, status, count, cursor, userId }) => {\r\n try {\r\n const result = await taskApi.listTasks(\r\n categoryId ?? \"default\",\r\n userId ?? \"me\",\r\n count ?? 50,\r\n cursor,\r\n status ?? \"ALL\"\r\n );\r\n const tasks = result.tasks.map((t) => ({\r\n taskId: t.taskId,\r\n title: t.title,\r\n status: t.status,\r\n dueDate: t.dueDate,\r\n assignor: t.assignorName ?? t.assignorId,\r\n created: t.createdTime,\r\n }));\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify({ tasks, count: tasks.length, hasMore: !!result.responseMetaData?.nextCursor, nextCursor: result.responseMetaData?.nextCursor ?? null }) }],\r\n };\r\n } catch (err) {\r\n return {\r\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"task.list\") }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n\r\n // Tool 15: 할 일 생성\r\n server.tool(\r\n \"nworks_task_create\",\r\n \"할 일(TODO)을 새로 만듭니다. '할 일 추가해줘', 'TODO 등록해줘' 등의 요청에 사용. 기본적으로 자기 자신에게 할당. User OAuth 인증 필요 (task + user.read scope)\",\r\n {\r\n title: z.string().describe(\"할 일 제목\"),\r\n content: z.string().optional().describe(\"할 일 내용\"),\r\n dueDate: z.string().optional().describe(\"마감일 (YYYY-MM-DD)\"),\r\n categoryId: z.string().optional().describe(\"카테고리 ID\"),\r\n assigneeIds: z.array(z.string()).optional().describe(\"담당자 user ID 목록 (미지정 시 자기 자신)\"),\r\n userId: z.string().optional().describe(\"생성자 user ID (미지정 시 me)\"),\r\n },\r\n async ({ title, content, dueDate, categoryId, assigneeIds, userId }) => {\r\n try {\r\n const result = await taskApi.createTask({\r\n title,\r\n content,\r\n dueDate,\r\n categoryId,\r\n assigneeIds,\r\n userId: userId ?? \"me\",\r\n });\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify({ success: true, taskId: result.taskId, title: result.title, status: result.status, dueDate: result.dueDate }) }],\r\n };\r\n } catch (err) {\r\n return {\r\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"task.create\") }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n\r\n // Tool 16: 할 일 수정\r\n server.tool(\r\n \"nworks_task_update\",\r\n \"할 일을 수정하거나 완료 처리합니다. '할 일 완료 처리해줘', '마감일 변경해줘' 등의 요청에 사용. taskId는 nworks_task_list로 조회 가능. User OAuth 인증 필요 (task + user.read scope)\",\r\n {\r\n taskId: z.string().describe(\"할 일 ID (nworks_task_list로 조회 가능)\"),\r\n status: z.enum([\"done\", \"todo\"]).optional().describe(\"상태 변경: done(완료) 또는 todo(미완료)\"),\r\n title: z.string().optional().describe(\"새 제목\"),\r\n content: z.string().optional().describe(\"새 내용\"),\r\n dueDate: z.string().optional().describe(\"새 마감일 (YYYY-MM-DD)\"),\r\n },\r\n async ({ taskId, status, title, content, dueDate }) => {\r\n try {\r\n // 상태 변경\r\n if (status) {\r\n if (status === \"done\") {\r\n await taskApi.completeTask(taskId);\r\n } else {\r\n await taskApi.incompleteTask(taskId);\r\n }\r\n }\r\n\r\n // 필드 수정\r\n if (title !== undefined || content !== undefined || dueDate !== undefined) {\r\n const result = await taskApi.updateTask({ taskId, title, content, dueDate });\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify({ success: true, taskId: result.taskId, title: result.title, status: result.status, dueDate: result.dueDate }) }],\r\n };\r\n }\r\n\r\n if (status) {\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify({ success: true, taskId, status: status === \"done\" ? \"DONE\" : \"TODO\" }) }],\r\n };\r\n }\r\n\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify({ error: true, message: \"status, title, content, dueDate 중 하나 이상을 지정하세요.\" }) }],\r\n isError: true,\r\n };\r\n } catch (err) {\r\n return {\r\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"task.update\") }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n\r\n // Tool 17: 할 일 삭제\r\n server.tool(\r\n \"nworks_task_delete\",\r\n \"할 일을 삭제합니다. taskId는 nworks_task_list로 조회 가능. User OAuth 인증 필요 (task + user.read scope)\",\r\n {\r\n taskId: z.string().describe(\"삭제할 할 일 ID (nworks_task_list로 조회 가능)\"),\r\n },\r\n async ({ taskId }) => {\r\n try {\r\n await taskApi.deleteTask(taskId);\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify({ success: true, taskId, message: \"할 일이 삭제되었습니다\" }) }],\r\n };\r\n } catch (err) {\r\n return {\r\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"task.delete\") }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n\r\n // Tool 18: 게시판 목록\r\n server.tool(\r\n \"nworks_board_list\",\r\n \"NAVER WORKS 게시판 목록을 조회합니다. '게시판 뭐 있어?', '공지사항 게시판 찾아줘' 등의 요청에 사용. User OAuth 인증 필요 (board.read scope)\",\r\n {\r\n count: z.number().optional().describe(\"페이지당 항목 수 (기본: 20)\"),\r\n cursor: z.string().optional().describe(\"페이지네이션 커서\"),\r\n },\r\n async ({ count, cursor }) => {\r\n try {\r\n const result = await boardApi.listBoards(count ?? 20, cursor);\r\n const boards = result.boards.map((b) => ({\r\n boardId: b.boardId,\r\n boardName: b.boardName,\r\n description: b.description ?? \"\",\r\n }));\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify({ boards, count: boards.length, hasMore: !!result.responseMetaData?.nextCursor, nextCursor: result.responseMetaData?.nextCursor ?? null }) }],\r\n };\r\n } catch (err) {\r\n return {\r\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"board.list\") }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n\r\n // Tool 19: 게시판 글 목록\r\n server.tool(\r\n \"nworks_board_posts\",\r\n \"게시판의 글 목록을 조회합니다. '게시판 글 보여줘', '공지사항 확인' 등의 요청에 사용. boardId는 nworks_board_list로 조회 가능. User OAuth 인증 필요 (board.read scope)\",\r\n {\r\n boardId: z.string().describe(\"게시판 ID (nworks_board_list로 조회 가능)\"),\r\n count: z.number().optional().describe(\"페이지당 항목 수 (기본: 20, 최대: 40)\"),\r\n cursor: z.string().optional().describe(\"페이지네이션 커서\"),\r\n },\r\n async ({ boardId, count, cursor }) => {\r\n try {\r\n const result = await boardApi.listPosts(boardId, count ?? 20, cursor);\r\n const posts = result.posts.map((p) => ({\r\n postId: p.postId,\r\n title: p.title,\r\n userName: p.userName ?? \"\",\r\n readCount: p.readCount ?? 0,\r\n commentCount: p.commentCount ?? 0,\r\n createdTime: p.createdTime ?? \"\",\r\n }));\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify({ posts, count: posts.length, hasMore: !!result.responseMetaData?.nextCursor, nextCursor: result.responseMetaData?.nextCursor ?? null }) }],\r\n };\r\n } catch (err) {\r\n return {\r\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"board.posts\") }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n\r\n // Tool 20: 게시판 글 상세 조회\r\n server.tool(\r\n \"nworks_board_read\",\r\n \"게시판 글의 상세 내용을 조회합니다. postId는 nworks_board_posts로 조회 가능. User OAuth 인증 필요 (board.read scope)\",\r\n {\r\n boardId: z.string().describe(\"게시판 ID (nworks_board_list로 조회 가능)\"),\r\n postId: z.string().describe(\"글 ID (nworks_board_posts로 조회 가능)\"),\r\n },\r\n async ({ boardId, postId }) => {\r\n try {\r\n const post = await boardApi.readPost(boardId, postId);\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify({\r\n postId: post.postId,\r\n boardId: post.boardId,\r\n title: post.title,\r\n body: post.body ?? \"\",\r\n userName: post.userName ?? \"\",\r\n readCount: post.readCount ?? 0,\r\n commentCount: post.commentCount ?? 0,\r\n createdTime: post.createdTime ?? \"\",\r\n updatedTime: post.updatedTime ?? \"\",\r\n }) }],\r\n };\r\n } catch (err) {\r\n return {\r\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"board.read\") }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n\r\n // Tool 21: 게시판 글 작성\r\n server.tool(\r\n \"nworks_board_create\",\r\n \"게시판에 글을 작성합니다. '게시판에 글 올려줘', '공지 작성해줘' 등의 요청에 사용. boardId는 nworks_board_list로 조회 가능. User OAuth 인증 필요 (board scope)\",\r\n {\r\n boardId: z.string().describe(\"게시판 ID (nworks_board_list로 조회 가능)\"),\r\n title: z.string().describe(\"글 제목\"),\r\n body: z.string().optional().describe(\"글 본문\"),\r\n enableComment: z.boolean().optional().describe(\"댓글 허용 (기본: true)\"),\r\n sendNotifications: z.boolean().optional().describe(\"알림 발송 (기본: false)\"),\r\n },\r\n async ({ boardId, title, body, enableComment, sendNotifications }) => {\r\n try {\r\n const post = await boardApi.createPost({\r\n boardId,\r\n title,\r\n body,\r\n enableComment,\r\n sendNotifications,\r\n });\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify({ success: true, postId: post.postId, boardId: post.boardId, title: post.title }) }],\r\n };\r\n } catch (err) {\r\n return {\r\n content: [{ type: \"text\" as const, text: mcpErrorHint(err, \"board.create\") }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n\r\n // Tool 22: User OAuth 로그인\r\n server.tool(\r\n \"nworks_login_user\",\r\n \"User OAuth 로그인을 시작합니다. 반환된 URL을 브라우저에서 열어 NAVER WORKS에 로그인하세요. 로그인 완료 후 자동으로 토큰이 저장됩니다. 중요: scope를 지정하지 마세요. 기본값이 모든 API(캘린더, 메일, 할일, 드라이브, 게시판)를 포함하므로 한 번 로그인으로 전체 기능을 사용할 수 있습니다. scope를 좁게 지정하면 다른 기능 사용 시 재로그인이 필요합니다.\",\r\n {\r\n scope: z\r\n .string()\r\n .optional()\r\n .describe(\"지정하지 마세요 (기본값이 전체 scope 포함). 특수한 경우에만 사용\"),\r\n },\r\n async ({ scope }) => {\r\n const DEFAULT_SCOPE = \"calendar calendar.read file file.read mail mail.read task task.read user.read board board.read\";\r\n try {\r\n const creds = await loadCredentials();\r\n\r\n // scope 의존성 자동 확장\r\n // - calendar 쓰기는 calendar.read 필요 (수정/삭제 시 기존 일정 조회)\r\n // - task 쓰기는 user.read 필요 (/users/me 호출)\r\n const SCOPE_DEPS: Record<string, string[]> = {\r\n calendar: [\"calendar.read\"],\r\n task: [\"user.read\"],\r\n \"task.read\": [\"user.read\"],\r\n };\r\n\r\n const expandScopes = (scopes: string[]): string[] => {\r\n const expanded = new Set(scopes);\r\n for (const s of scopes) {\r\n const deps = SCOPE_DEPS[s];\r\n if (deps) deps.forEach((d) => expanded.add(d));\r\n }\r\n return [...expanded];\r\n };\r\n\r\n // 기존 토큰의 scope와 합치기\r\n const existingToken = await loadUserToken();\r\n const existingScopes = existingToken?.scope?.split(\" \").filter(Boolean) ?? [];\r\n const requestedScopes = expandScopes((scope ?? DEFAULT_SCOPE).split(\" \").filter(Boolean));\r\n const mergedScopes = [...new Set([...existingScopes, ...requestedScopes])].join(\" \");\r\n\r\n const state = Math.random().toString(36).substring(2);\r\n const authorizeUrl = buildAuthorizeUrl(creds.clientId, mergedScopes, state);\r\n\r\n // 콜백 서버를 백그라운드로 시작 (토큰 교환 및 저장까지 자동 처리)\r\n startOAuthCallbackServer(creds.clientId, creds.clientSecret)\r\n .then((token) =>\r\n saveUserToken({\r\n accessToken: token.accessToken,\r\n refreshToken: token.refreshToken,\r\n expiresAt: token.expiresAt,\r\n scope: token.scope,\r\n })\r\n )\r\n .then(() => {\r\n console.error(\"[nworks] User OAuth login successful. Token saved.\");\r\n })\r\n .catch((err: Error) => {\r\n console.error(`[nworks] User OAuth login failed: ${err.message}`);\r\n });\r\n\r\n return {\r\n content: [\r\n {\r\n type: \"text\" as const,\r\n text: JSON.stringify({\r\n message:\r\n \"아래 URL을 브라우저에서 열어 NAVER WORKS에 로그인하세요. 로그인 완료 후 자동으로 토큰이 저장됩니다. (제한시간: 120초)\",\r\n loginUrl: authorizeUrl,\r\n scope: mergedScopes,\r\n callbackPort: 9876,\r\n timeout: \"120초\",\r\n }),\r\n },\r\n ],\r\n };\r\n } catch (err) {\r\n return {\r\n content: [{ type: \"text\" as const, text: mcpErrorHint(err) }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n\r\n // Tool 23: 인증 상태\r\n server.tool(\r\n \"nworks_whoami\",\r\n \"현재 인증된 NAVER WORKS 계정 정보와 토큰 유효 상태를 확인합니다. 인증 문제 진단 시 먼저 호출\",\r\n {},\r\n async () => {\r\n try {\r\n const creds = await loadCredentials();\r\n const token = await loadToken();\r\n const userToken = await loadUserToken();\r\n const isValid = token\r\n ? token.expiresAt > Date.now() / 1000\r\n : false;\r\n const userTokenValid = userToken\r\n ? userToken.expiresAt > Date.now() / 1000\r\n : false;\r\n\r\n const info = {\r\n serviceAccount: creds.serviceAccount ?? null,\r\n clientId: creds.clientId,\r\n botId: creds.botId ?? null,\r\n tokenValid: isValid,\r\n userOAuth: userToken\r\n ? { valid: userTokenValid, scope: userToken.scope }\r\n : null,\r\n };\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify(info) }],\r\n };\r\n } catch (err) {\r\n return {\r\n content: [{ type: \"text\" as const, text: mcpErrorHint(err) }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n\r\n // Tool 24: 로그아웃\r\n server.tool(\r\n \"nworks_logout\",\r\n \"저장된 NAVER WORKS 인증 정보와 토큰을 모두 삭제합니다\",\r\n {},\r\n async () => {\r\n try {\r\n await clearCredentials();\r\n return {\r\n content: [\r\n {\r\n type: \"text\" as const,\r\n text: JSON.stringify({\r\n success: true,\r\n message: \"인증 정보와 토큰이 모두 삭제되었습니다. 다시 사용하려면 nworks_setup tool로 재설정하세요.\",\r\n }),\r\n },\r\n ],\r\n };\r\n } catch (err) {\r\n return {\r\n content: [{ type: \"text\" as const, text: mcpErrorHint(err) }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n\r\n // Tool 25: 진단\r\n server.tool(\r\n \"nworks_doctor\",\r\n \"NAVER WORKS 연결 상태를 진단합니다. 인증 정보, 토큰, Private Key, API 연결을 점검합니다.\",\r\n {},\r\n async () => {\r\n try {\r\n const results = await runChecks(\"default\");\r\n return {\r\n content: [{ type: \"text\" as const, text: JSON.stringify(results) }],\r\n };\r\n } catch (err) {\r\n return {\r\n content: [{ type: \"text\" as const, text: mcpErrorHint(err) }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n}\r\n","export class AuthError extends Error {\r\n constructor(message: string) {\r\n super(message);\r\n this.name = \"AuthError\";\r\n }\r\n}\r\n\r\nexport class ApiError extends Error {\r\n public readonly code: string;\r\n public readonly statusCode: number;\r\n\r\n constructor(code: string, description: string, statusCode: number) {\r\n super(description);\r\n this.name = \"ApiError\";\r\n this.code = code;\r\n this.statusCode = statusCode;\r\n }\r\n}\r\n","import { readFile, writeFile, mkdir } from \"node:fs/promises\";\r\nimport { existsSync } from \"node:fs\";\r\nimport { homedir } from \"node:os\";\r\nimport { join } from \"node:path\";\r\nimport { AuthError } from \"../utils/error.js\";\r\n\r\nexport interface Credentials {\r\n clientId: string;\r\n clientSecret: string;\r\n serviceAccount?: string;\r\n privateKeyPath?: string;\r\n botId?: string;\r\n domainId?: string;\r\n}\r\n\r\nexport function hasServiceAccountCreds(\r\n creds: Credentials\r\n): creds is Credentials & Required<Pick<Credentials, \"serviceAccount\" | \"privateKeyPath\" | \"botId\">> {\r\n return !!(creds.serviceAccount && creds.privateKeyPath && creds.botId);\r\n}\r\n\r\nexport interface TokenData {\r\n accessToken: string;\r\n expiresAt: number;\r\n}\r\n\r\nexport interface UserTokenData {\r\n accessToken: string;\r\n refreshToken: string;\r\n expiresAt: number;\r\n scope: string;\r\n}\r\n\r\nconst CONFIG_DIR = join(homedir(), \".config\", \"nworks\");\r\nconst CREDENTIALS_PATH = join(CONFIG_DIR, \"credentials.json\");\r\nconst TOKEN_PATH = join(CONFIG_DIR, \"token.json\");\r\nconst USER_TOKEN_PATH = join(CONFIG_DIR, \"user-token.json\");\r\n\r\nasync function ensureConfigDir(): Promise<void> {\r\n if (!existsSync(CONFIG_DIR)) {\r\n await mkdir(CONFIG_DIR, { recursive: true });\r\n }\r\n}\r\n\r\nexport function getCredentialsFromEnv(): Credentials | null {\r\n const clientId = process.env[\"NWORKS_CLIENT_ID\"];\r\n const clientSecret = process.env[\"NWORKS_CLIENT_SECRET\"];\r\n\r\n if (!clientId || !clientSecret) return null;\r\n\r\n return {\r\n clientId,\r\n clientSecret,\r\n serviceAccount: process.env[\"NWORKS_SERVICE_ACCOUNT\"],\r\n privateKeyPath: process.env[\"NWORKS_PRIVATE_KEY_PATH\"],\r\n botId: process.env[\"NWORKS_BOT_ID\"],\r\n domainId: process.env[\"NWORKS_DOMAIN_ID\"],\r\n };\r\n}\r\n\r\nexport async function loadCredentials(\r\n profile = \"default\"\r\n): Promise<Credentials> {\r\n const envCreds = getCredentialsFromEnv();\r\n if (envCreds) return envCreds;\r\n\r\n if (!existsSync(CREDENTIALS_PATH)) {\r\n throw new AuthError(\r\n \"Not logged in. Run `nworks login` or set environment variables.\"\r\n );\r\n }\r\n\r\n const raw = await readFile(CREDENTIALS_PATH, \"utf-8\");\r\n const profiles = JSON.parse(raw) as Record<string, Credentials>;\r\n const creds = profiles[profile];\r\n\r\n if (!creds) {\r\n throw new AuthError(`Profile \"${profile}\" not found in credentials.`);\r\n }\r\n\r\n return creds;\r\n}\r\n\r\nexport async function saveCredentials(\r\n creds: Credentials,\r\n profile = \"default\"\r\n): Promise<void> {\r\n await ensureConfigDir();\r\n\r\n let profiles: Record<string, Credentials> = {};\r\n if (existsSync(CREDENTIALS_PATH)) {\r\n const raw = await readFile(CREDENTIALS_PATH, \"utf-8\");\r\n profiles = JSON.parse(raw) as Record<string, Credentials>;\r\n }\r\n\r\n profiles[profile] = creds;\r\n await writeFile(CREDENTIALS_PATH, JSON.stringify(profiles, null, 2), \"utf-8\");\r\n}\r\n\r\nexport async function loadToken(profile = \"default\"): Promise<TokenData | null> {\r\n if (!existsSync(TOKEN_PATH)) return null;\r\n\r\n const raw = await readFile(TOKEN_PATH, \"utf-8\");\r\n const tokens = JSON.parse(raw) as Record<string, unknown>;\r\n const entry = tokens[profile] as Record<string, unknown> | undefined;\r\n if (!entry) return null;\r\n\r\n return {\r\n accessToken: String(entry[\"accessToken\"]),\r\n expiresAt: Number(entry[\"expiresAt\"]),\r\n };\r\n}\r\n\r\nexport async function saveToken(\r\n token: TokenData,\r\n profile = \"default\"\r\n): Promise<void> {\r\n await ensureConfigDir();\r\n\r\n let tokens: Record<string, TokenData> = {};\r\n if (existsSync(TOKEN_PATH)) {\r\n const raw = await readFile(TOKEN_PATH, \"utf-8\");\r\n tokens = JSON.parse(raw) as Record<string, TokenData>;\r\n }\r\n\r\n tokens[profile] = token;\r\n await writeFile(TOKEN_PATH, JSON.stringify(tokens, null, 2), \"utf-8\");\r\n}\r\n\r\nexport async function loadUserToken(profile = \"default\"): Promise<UserTokenData | null> {\r\n if (!existsSync(USER_TOKEN_PATH)) return null;\r\n\r\n const raw = await readFile(USER_TOKEN_PATH, \"utf-8\");\r\n const tokens = JSON.parse(raw) as Record<string, unknown>;\r\n const entry = tokens[profile] as Record<string, unknown> | undefined;\r\n if (!entry) return null;\r\n\r\n return {\r\n accessToken: String(entry[\"accessToken\"]),\r\n refreshToken: String(entry[\"refreshToken\"]),\r\n expiresAt: Number(entry[\"expiresAt\"]),\r\n scope: String(entry[\"scope\"] ?? \"\"),\r\n };\r\n}\r\n\r\nexport async function saveUserToken(\r\n token: UserTokenData,\r\n profile = \"default\"\r\n): Promise<void> {\r\n await ensureConfigDir();\r\n\r\n let tokens: Record<string, UserTokenData> = {};\r\n if (existsSync(USER_TOKEN_PATH)) {\r\n const raw = await readFile(USER_TOKEN_PATH, \"utf-8\");\r\n tokens = JSON.parse(raw) as Record<string, UserTokenData>;\r\n }\r\n\r\n tokens[profile] = token;\r\n await writeFile(USER_TOKEN_PATH, JSON.stringify(tokens, null, 2), \"utf-8\");\r\n}\r\n\r\nexport async function clearCredentials(profile = \"default\"): Promise<void> {\r\n if (existsSync(CREDENTIALS_PATH)) {\r\n const raw = await readFile(CREDENTIALS_PATH, \"utf-8\");\r\n const profiles = JSON.parse(raw) as Record<string, Credentials>;\r\n delete profiles[profile];\r\n await writeFile(\r\n CREDENTIALS_PATH,\r\n JSON.stringify(profiles, null, 2),\r\n \"utf-8\"\r\n );\r\n }\r\n\r\n if (existsSync(TOKEN_PATH)) {\r\n const raw = await readFile(TOKEN_PATH, \"utf-8\");\r\n const tokens = JSON.parse(raw) as Record<string, TokenData>;\r\n delete tokens[profile];\r\n await writeFile(TOKEN_PATH, JSON.stringify(tokens, null, 2), \"utf-8\");\r\n }\r\n\r\n if (existsSync(USER_TOKEN_PATH)) {\r\n const raw = await readFile(USER_TOKEN_PATH, \"utf-8\");\r\n const tokens = JSON.parse(raw) as Record<string, UserTokenData>;\r\n delete tokens[profile];\r\n await writeFile(USER_TOKEN_PATH, JSON.stringify(tokens, null, 2), \"utf-8\");\r\n }\r\n}\r\n","import { readFile } from \"node:fs/promises\";\r\nimport jwt from \"jsonwebtoken\";\r\nimport type { Credentials } from \"./config.js\";\r\nimport { AuthError } from \"../utils/error.js\";\r\n\r\nexport async function createJWT(creds: Credentials): Promise<string> {\r\n if (!creds.serviceAccount || !creds.privateKeyPath) {\r\n throw new AuthError(\r\n \"Service Account credentials required for bot authentication.\\n\" +\r\n \"Run `nworks login` with --service-account and --private-key flags.\"\r\n );\r\n }\r\n\r\n const privateKey = await readFile(creds.privateKeyPath, \"utf-8\");\r\n\r\n const now = Math.floor(Date.now() / 1000);\r\n const payload = {\r\n iss: creds.clientId,\r\n sub: creds.serviceAccount,\r\n iat: now,\r\n exp: now + 3600,\r\n };\r\n\r\n return jwt.sign(payload, privateKey, { algorithm: \"RS256\" });\r\n}\r\n","import { AuthError } from \"../utils/error.js\";\r\nimport { loadCredentials, loadToken, saveToken } from \"./config.js\";\r\nimport { createJWT } from \"./jwt.js\";\r\n\r\nconst AUTH_URL = \"https://auth.worksmobile.com/oauth2/v2.0/token\";\r\n\r\nexport async function getValidToken(profile = \"default\"): Promise<string> {\r\n const cached = await loadToken(profile);\r\n\r\n if (cached && cached.expiresAt > Date.now() / 1000 + 300) {\r\n return cached.accessToken;\r\n }\r\n\r\n return refreshToken(profile);\r\n}\r\n\r\nexport async function refreshToken(profile = \"default\"): Promise<string> {\r\n const creds = await loadCredentials(profile);\r\n const assertion = await createJWT(creds);\r\n\r\n const body = new URLSearchParams({\r\n grant_type: \"urn:ietf:params:oauth:grant-type:jwt-bearer\",\r\n assertion,\r\n client_id: creds.clientId,\r\n client_secret: creds.clientSecret,\r\n scope: process.env[\"NWORKS_SCOPE\"] ?? \"bot bot.read user.read\",\r\n });\r\n\r\n const res = await fetch(AUTH_URL, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\r\n body: body.toString(),\r\n });\r\n\r\n if (!res.ok) {\r\n const text = await res.text();\r\n throw new AuthError(`Token exchange failed (${res.status}): ${text}`);\r\n }\r\n\r\n const data = (await res.json()) as {\r\n access_token: string;\r\n token_type: string;\r\n expires_in: number | string;\r\n };\r\n\r\n const expiresIn = Number(data.expires_in);\r\n const tokenData = {\r\n accessToken: data.access_token,\r\n expiresAt: Math.floor(Date.now() / 1000) + expiresIn,\r\n };\r\n\r\n await saveToken(tokenData, profile);\r\n return tokenData.accessToken;\r\n}\r\n","import { ApiError, AuthError } from \"../utils/error.js\";\r\nimport { getValidToken, refreshToken } from \"../auth/token.js\";\r\n\r\nconst BASE_URL = \"https://www.worksapis.com/v1.0\";\r\nconst MAX_RETRIES = 3;\r\n\r\ninterface RequestOptions {\r\n method: string;\r\n path: string;\r\n body?: unknown;\r\n profile?: string;\r\n}\r\n\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n\r\nexport async function request<T>(\r\n opts: RequestOptions,\r\n _retryCount = 0\r\n): Promise<T> {\r\n const { method, path, body, profile = \"default\" } = opts;\r\n const token = await getValidToken(profile);\r\n\r\n const url = `${BASE_URL}${path}`;\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] ${method} ${url}`);\r\n }\r\n\r\n const res = await fetch(url, {\r\n method,\r\n headers: {\r\n Authorization: `Bearer ${token}`,\r\n \"Content-Type\": \"application/json\",\r\n },\r\n body: body ? JSON.stringify(body) : undefined,\r\n });\r\n\r\n if (res.status === 401 && _retryCount === 0) {\r\n await refreshToken(profile);\r\n return request<T>(opts, _retryCount + 1);\r\n }\r\n\r\n if (res.status === 429 && _retryCount < MAX_RETRIES) {\r\n const retryAfter = parseInt(res.headers.get(\"Retry-After\") ?? \"5\", 10);\r\n await sleep(retryAfter * 1000);\r\n return request<T>(opts, _retryCount + 1);\r\n }\r\n\r\n if (!res.ok) {\r\n let code = \"UNKNOWN\";\r\n let description = `HTTP ${res.status}`;\r\n\r\n try {\r\n const errorBody = (await res.json()) as {\r\n code?: string;\r\n description?: string;\r\n };\r\n code = errorBody.code ?? code;\r\n description = errorBody.description ?? description;\r\n } catch {\r\n // ignore\r\n }\r\n\r\n if (res.status === 401) {\r\n throw new AuthError(description);\r\n }\r\n throw new ApiError(code, description, res.status);\r\n }\r\n\r\n const text = await res.text();\r\n if (!text) {\r\n return undefined as T;\r\n }\r\n\r\n return JSON.parse(text) as T;\r\n}\r\n","import { request } from \"./client.js\";\r\nimport { loadCredentials } from \"../auth/config.js\";\r\n\r\nexport type MessageType = \"text\" | \"button\" | \"list\";\r\n\r\nexport interface SendOptions {\r\n to?: string;\r\n channel?: string;\r\n text: string;\r\n type?: MessageType;\r\n actions?: string;\r\n elements?: string;\r\n profile?: string;\r\n}\r\n\r\nexport interface SendResult {\r\n success: boolean;\r\n messageId?: string;\r\n}\r\n\r\nexport interface MemberListResult {\r\n members: string[];\r\n responseMetaData?: { nextCursor?: string };\r\n}\r\n\r\nfunction buildContent(opts: SendOptions): Record<string, unknown> {\r\n const type = opts.type ?? \"text\";\r\n\r\n if (type === \"text\") {\r\n return { type: \"text\", text: opts.text };\r\n }\r\n\r\n if (type === \"button\") {\r\n const actions = opts.actions ? JSON.parse(opts.actions) as unknown[] : [];\r\n return {\r\n type: \"button_template\",\r\n contentText: opts.text,\r\n actions,\r\n };\r\n }\r\n\r\n if (type === \"list\") {\r\n const elements = opts.elements ? JSON.parse(opts.elements) as unknown[] : [];\r\n return {\r\n type: \"list_template\",\r\n coverData: { text: opts.text },\r\n elements,\r\n };\r\n }\r\n\r\n return { type: \"text\", text: opts.text };\r\n}\r\n\r\nexport async function send(opts: SendOptions): Promise<SendResult> {\r\n const profile = opts.profile ?? \"default\";\r\n const creds = await loadCredentials(profile);\r\n\r\n if (!creds.botId) {\r\n throw new Error(\r\n \"Bot ID is required for sending messages.\\n\" +\r\n \"Run `nworks login` with --bot-id flag to set up bot credentials.\"\r\n );\r\n }\r\n\r\n const content = buildContent(opts);\r\n const body = { content };\r\n\r\n if (opts.to) {\r\n const result = await request<{ messageId?: string }>({\r\n method: \"POST\",\r\n path: `/bots/${creds.botId}/users/${opts.to}/messages`,\r\n body,\r\n profile,\r\n });\r\n return { success: true, messageId: result?.messageId };\r\n }\r\n if (opts.channel) {\r\n const result = await request<{ messageId?: string }>({\r\n method: \"POST\",\r\n path: `/bots/${creds.botId}/channels/${opts.channel}/messages`,\r\n body,\r\n profile,\r\n });\r\n return { success: true, messageId: result?.messageId };\r\n }\r\n\r\n throw new Error(\"Either --to (userId) or --channel (channelId) is required.\");\r\n}\r\n\r\n\r\nexport async function listMembers(\r\n channelId: string,\r\n profile = \"default\"\r\n): Promise<MemberListResult> {\r\n const creds = await loadCredentials(profile);\r\n\r\n if (!creds.botId) {\r\n throw new Error(\r\n \"Bot ID is required for listing channel members.\\n\" +\r\n \"Run `nworks login` with --bot-id flag to set up bot credentials.\"\r\n );\r\n }\r\n\r\n const result = await request<{ members: string[]; responseMetaData?: { nextCursor?: string } }>({\r\n method: \"GET\",\r\n path: `/bots/${creds.botId}/channels/${channelId}/members`,\r\n profile,\r\n });\r\n return { members: result.members ?? [], responseMetaData: result.responseMetaData };\r\n}\r\n","import { request } from \"./client.js\";\r\n\r\nexport interface User {\r\n userId: string;\r\n userName?: {\r\n lastName?: string;\r\n firstName?: string;\r\n };\r\n email?: string;\r\n organizations?: Array<{\r\n organizationName?: string;\r\n primary?: boolean;\r\n }>;\r\n isAdministrator?: boolean;\r\n isDeleted?: boolean;\r\n}\r\n\r\nexport interface UserListResult {\r\n users: User[];\r\n responseMetaData?: { nextCursor?: string };\r\n}\r\n\r\nexport async function listUsers(\r\n profile = \"default\"\r\n): Promise<UserListResult> {\r\n const result = await request<{\r\n users: User[];\r\n responseMetaData?: { nextCursor?: string };\r\n }>({\r\n method: \"GET\",\r\n path: \"/users\",\r\n profile,\r\n });\r\n return { users: result.users ?? [], responseMetaData: result.responseMetaData };\r\n}\r\n","import { randomUUID } from \"node:crypto\";\r\nimport { ApiError, AuthError } from \"../utils/error.js\";\r\nimport { getValidUserToken } from \"../auth/token-user.js\";\r\n\r\nconst BASE_URL = \"https://www.worksapis.com/v1.0\";\r\n\r\nexport interface CalendarEvent {\r\n eventId: string;\r\n summary: string;\r\n description?: string;\r\n location?: string;\r\n start: { date?: string; dateTime?: string; timeZone?: string };\r\n end: { date?: string; dateTime?: string; timeZone?: string };\r\n transparency?: string;\r\n visibility?: string;\r\n attendees?: Array<{ email?: string; displayName?: string }>;\r\n createdTime?: { dateTime?: string; timeZone?: string };\r\n updatedTime?: { dateTime?: string; timeZone?: string };\r\n viewUrl?: string;\r\n}\r\n\r\nexport interface EventListResult {\r\n events: Array<{\r\n eventComponents: CalendarEvent[];\r\n organizerCalendarId?: string;\r\n }>;\r\n}\r\n\r\nexport interface CreateEventOptions {\r\n summary: string;\r\n start: string;\r\n end: string;\r\n timeZone?: string;\r\n description?: string;\r\n location?: string;\r\n attendees?: Array<{ email: string; displayName?: string }>;\r\n transparency?: \"OPAQUE\" | \"TRANSPARENT\";\r\n visibility?: \"PUBLIC\" | \"PRIVATE\";\r\n sendNotification?: boolean;\r\n userId?: string;\r\n profile?: string;\r\n}\r\n\r\nexport interface UpdateEventOptions {\r\n eventId: string;\r\n summary?: string;\r\n start?: string;\r\n end?: string;\r\n timeZone?: string;\r\n description?: string;\r\n location?: string;\r\n attendees?: Array<{ email: string; displayName?: string }>;\r\n transparency?: \"OPAQUE\" | \"TRANSPARENT\";\r\n visibility?: \"PUBLIC\" | \"PRIVATE\";\r\n sendNotification?: boolean;\r\n userId?: string;\r\n profile?: string;\r\n}\r\n\r\nasync function authedFetch(\r\n url: string,\r\n init: RequestInit,\r\n profile: string\r\n): Promise<Response> {\r\n const token = await getValidUserToken(profile);\r\n const headers = new Headers(init.headers);\r\n headers.set(\"Authorization\", `Bearer ${token}`);\r\n return fetch(url, { ...init, headers });\r\n}\r\n\r\nasync function handleError(res: Response): Promise<never> {\r\n if (res.status === 401) {\r\n throw new AuthError(\"User token expired. Run `nworks login --user --scope calendar` again.\");\r\n }\r\n let code = \"UNKNOWN\";\r\n let description = `HTTP ${res.status}`;\r\n try {\r\n const body = (await res.json()) as { code?: string; description?: string };\r\n code = body.code ?? code;\r\n description = body.description ?? description;\r\n } catch {\r\n // ignore\r\n }\r\n throw new ApiError(code, description, res.status);\r\n}\r\n\r\nfunction generateEventId(): string {\r\n return `event-${randomUUID()}`;\r\n}\r\n\r\n/** 초가 없으면 :00 추가 (API 요구사항) */\r\nfunction normalizeDateTime(dt: string): string {\r\n const match = dt.match(/^(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2})([+-]\\d{2}:\\d{2}|Z)?$/);\r\n if (match) {\r\n return `${match[1]}:00${match[2] ?? \"\"}`;\r\n }\r\n return dt;\r\n}\r\n\r\nexport async function listEvents(\r\n fromDateTime: string,\r\n untilDateTime: string,\r\n userId = \"me\",\r\n profile = \"default\"\r\n): Promise<EventListResult> {\r\n const from = encodeURIComponent(fromDateTime);\r\n const until = encodeURIComponent(untilDateTime);\r\n\r\n const url = `${BASE_URL}/users/${userId}/calendar/events?fromDateTime=${from}&untilDateTime=${until}`;\r\n\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] GET ${url}`);\r\n }\r\n\r\n const res = await authedFetch(url, { method: \"GET\" }, profile);\r\n if (!res.ok) return handleError(res);\r\n\r\n const data = (await res.json()) as EventListResult;\r\n return { events: data.events ?? [] };\r\n}\r\n\r\nexport async function createEvent(\r\n opts: CreateEventOptions\r\n): Promise<{ eventComponents: CalendarEvent[]; organizerCalendarId?: string }> {\r\n const userId = opts.userId ?? \"me\";\r\n const profile = opts.profile ?? \"default\";\r\n const timeZone = opts.timeZone ?? \"Asia/Seoul\";\r\n\r\n const eventId = generateEventId();\r\n\r\n const eventComponent: Record<string, unknown> = {\r\n eventId,\r\n summary: opts.summary,\r\n start: { dateTime: normalizeDateTime(opts.start), timeZone },\r\n end: { dateTime: normalizeDateTime(opts.end), timeZone },\r\n };\r\n if (opts.description) eventComponent.description = opts.description;\r\n if (opts.location) eventComponent.location = opts.location;\r\n if (opts.transparency) eventComponent.transparency = opts.transparency;\r\n if (opts.visibility) eventComponent.visibility = opts.visibility;\r\n if (opts.attendees) {\r\n eventComponent.attendees = opts.attendees.map((a) => ({\r\n email: a.email,\r\n displayName: a.displayName ?? \"\",\r\n partstat: \"NEEDS-ACTION\",\r\n isOptional: false,\r\n isResource: false,\r\n }));\r\n }\r\n\r\n const body = {\r\n eventComponents: [eventComponent],\r\n sendNotification: opts.sendNotification ?? false,\r\n };\r\n\r\n const url = `${BASE_URL}/users/${userId}/calendar/events`;\r\n\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] POST ${url}`);\r\n console.error(`[nworks] Body: ${JSON.stringify(body, null, 2)}`);\r\n }\r\n\r\n const res = await authedFetch(\r\n url,\r\n {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify(body),\r\n },\r\n profile\r\n );\r\n\r\n if (res.status === 201) {\r\n return (await res.json()) as { eventComponents: CalendarEvent[]; organizerCalendarId?: string };\r\n }\r\n if (!res.ok) return handleError(res);\r\n return (await res.json()) as { eventComponents: CalendarEvent[]; organizerCalendarId?: string };\r\n}\r\n\r\nexport async function getEvent(\r\n eventId: string,\r\n userId = \"me\",\r\n profile = \"default\"\r\n): Promise<CalendarEvent> {\r\n const url = `${BASE_URL}/users/${userId}/calendar/events/${eventId}`;\r\n\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] GET ${url}`);\r\n }\r\n\r\n const res = await authedFetch(url, { method: \"GET\" }, profile);\r\n if (!res.ok) return handleError(res);\r\n\r\n const data = (await res.json()) as { eventComponents: CalendarEvent[] };\r\n const event = data.eventComponents[0];\r\n if (!event) throw new ApiError(\"NOT_FOUND\", \"Event not found\", 404);\r\n return event;\r\n}\r\n\r\nexport async function updateEvent(\r\n opts: UpdateEventOptions\r\n): Promise<void> {\r\n const userId = opts.userId ?? \"me\";\r\n const profile = opts.profile ?? \"default\";\r\n const timeZone = opts.timeZone ?? \"Asia/Seoul\";\r\n\r\n const existing = await getEvent(opts.eventId, userId, profile);\r\n\r\n const eventComponent: Record<string, unknown> = {\r\n eventId: opts.eventId,\r\n summary: opts.summary ?? existing.summary,\r\n start: opts.start\r\n ? { dateTime: normalizeDateTime(opts.start), timeZone }\r\n : existing.start,\r\n end: opts.end\r\n ? { dateTime: normalizeDateTime(opts.end), timeZone }\r\n : existing.end,\r\n };\r\n if (opts.description !== undefined) eventComponent.description = opts.description;\r\n else if (existing.description) eventComponent.description = existing.description;\r\n if (opts.location !== undefined) eventComponent.location = opts.location;\r\n else if (existing.location) eventComponent.location = existing.location;\r\n if (opts.transparency !== undefined) eventComponent.transparency = opts.transparency;\r\n if (opts.visibility !== undefined) eventComponent.visibility = opts.visibility;\r\n if (opts.attendees !== undefined) {\r\n eventComponent.attendees = opts.attendees.map((a) => ({\r\n email: a.email,\r\n displayName: a.displayName ?? \"\",\r\n partstat: \"NEEDS-ACTION\",\r\n isOptional: false,\r\n isResource: false,\r\n }));\r\n } else if (existing.attendees) {\r\n eventComponent.attendees = existing.attendees;\r\n }\r\n\r\n const body = {\r\n eventComponents: [eventComponent],\r\n sendNotification: opts.sendNotification ?? false,\r\n };\r\n\r\n const url = `${BASE_URL}/users/${userId}/calendar/events/${opts.eventId}`;\r\n\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] PUT ${url}`);\r\n console.error(`[nworks] Body: ${JSON.stringify(body, null, 2)}`);\r\n }\r\n\r\n const res = await authedFetch(\r\n url,\r\n {\r\n method: \"PUT\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify(body),\r\n },\r\n profile\r\n );\r\n\r\n if (!res.ok) return handleError(res);\r\n}\r\n\r\nexport async function deleteEvent(\r\n eventId: string,\r\n userId = \"me\",\r\n sendNotification = false,\r\n profile = \"default\"\r\n): Promise<void> {\r\n const params = new URLSearchParams();\r\n params.set(\"sendNotification\", String(sendNotification));\r\n\r\n const url = `${BASE_URL}/users/${userId}/calendar/events/${eventId}?${params.toString()}`;\r\n\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] DELETE ${url}`);\r\n }\r\n\r\n const res = await authedFetch(url, { method: \"DELETE\" }, profile);\r\n\r\n if (res.status === 204) return;\r\n if (!res.ok) return handleError(res);\r\n}\r\n","import { createServer, type IncomingMessage, type ServerResponse } from \"node:http\";\r\nimport { URL } from \"node:url\";\r\nimport { AuthError } from \"../utils/error.js\";\r\nimport { loadCredentials } from \"./config.js\";\r\n\r\nconst AUTH_URL = \"https://auth.worksmobile.com/oauth2/v2.0/authorize\";\r\nconst TOKEN_URL = \"https://auth.worksmobile.com/oauth2/v2.0/token\";\r\nconst REDIRECT_PORT = 9876;\r\nconst REDIRECT_URI = `http://localhost:${REDIRECT_PORT}/callback`;\r\n\r\ninterface UserTokenResult {\r\n accessToken: string;\r\n refreshToken: string;\r\n expiresAt: number;\r\n scope: string;\r\n}\r\n\r\nexport function buildAuthorizeUrl(clientId: string, scope: string, state: string): string {\r\n const params = new URLSearchParams({\r\n client_id: clientId,\r\n redirect_uri: REDIRECT_URI,\r\n scope,\r\n response_type: \"code\",\r\n state,\r\n });\r\n return `${AUTH_URL}?${params.toString()}`;\r\n}\r\n\r\n/**\r\n * Start local HTTP server and wait for OAuth callback with auth code.\r\n * Then exchange code for tokens.\r\n */\r\nexport async function startUserOAuthFlow(\r\n _scope: string,\r\n profile = \"default\"\r\n): Promise<UserTokenResult> {\r\n const creds = await loadCredentials(profile);\r\n const code = await waitForAuthCode();\r\n\r\n return exchangeCodeForToken(code, creds.clientId, creds.clientSecret);\r\n}\r\n\r\nfunction waitForAuthCode(): Promise<string> {\r\n return new Promise((resolve, reject) => {\r\n const timeout = setTimeout(() => {\r\n server.close();\r\n reject(new AuthError(\"OAuth login timed out (120s). Try again.\"));\r\n }, 120_000);\r\n\r\n const server = createServer((req: IncomingMessage, res: ServerResponse) => {\r\n const url = new URL(req.url ?? \"/\", `http://localhost:${REDIRECT_PORT}`);\r\n\r\n if (url.pathname !== \"/callback\") {\r\n res.writeHead(404);\r\n res.end(\"Not found\");\r\n return;\r\n }\r\n\r\n const code = url.searchParams.get(\"code\");\r\n const error = url.searchParams.get(\"error\");\r\n\r\n if (error) {\r\n res.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" });\r\n res.end(\"<h2>로그인 실패</h2><p>이 창을 닫아도 됩니다.</p>\");\r\n clearTimeout(timeout);\r\n server.close();\r\n reject(new AuthError(`OAuth error: ${error}`));\r\n return;\r\n }\r\n\r\n if (!code) {\r\n res.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\r\n res.end(\"<h2>잘못된 요청</h2><p>Authorization code가 없습니다.</p>\");\r\n clearTimeout(timeout);\r\n server.close();\r\n reject(new AuthError(\"Missing authorization code in callback.\"));\r\n return;\r\n }\r\n\r\n res.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" });\r\n res.end(\"<h2>로그인 성공!</h2><p>이 창을 닫고 터미널로 돌아가세요.</p>\");\r\n clearTimeout(timeout);\r\n server.close();\r\n resolve(code);\r\n });\r\n\r\n server.listen(REDIRECT_PORT, () => {\r\n // Server ready — caller opens browser\r\n });\r\n\r\n server.on(\"error\", (err) => {\r\n clearTimeout(timeout);\r\n reject(new AuthError(`Failed to start callback server on port ${REDIRECT_PORT}: ${err.message}`));\r\n });\r\n });\r\n}\r\n\r\nasync function exchangeCodeForToken(\r\n code: string,\r\n clientId: string,\r\n clientSecret: string\r\n): Promise<UserTokenResult> {\r\n const body = new URLSearchParams({\r\n grant_type: \"authorization_code\",\r\n code,\r\n client_id: clientId,\r\n client_secret: clientSecret,\r\n redirect_uri: REDIRECT_URI,\r\n });\r\n\r\n const res = await fetch(TOKEN_URL, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\r\n body: body.toString(),\r\n });\r\n\r\n if (!res.ok) {\r\n const text = await res.text();\r\n throw new AuthError(`Token exchange failed (${res.status}): ${text}`);\r\n }\r\n\r\n const data = (await res.json()) as {\r\n access_token: string;\r\n refresh_token: string;\r\n expires_in: number | string;\r\n scope: string;\r\n };\r\n\r\n return {\r\n accessToken: data.access_token,\r\n refreshToken: data.refresh_token,\r\n expiresAt: Math.floor(Date.now() / 1000) + Number(data.expires_in),\r\n scope: data.scope,\r\n };\r\n}\r\n\r\nexport async function refreshUserToken(\r\n refreshToken: string,\r\n profile = \"default\"\r\n): Promise<UserTokenResult> {\r\n const creds = await loadCredentials(profile);\r\n\r\n const body = new URLSearchParams({\r\n grant_type: \"refresh_token\",\r\n refresh_token: refreshToken,\r\n client_id: creds.clientId,\r\n client_secret: creds.clientSecret,\r\n });\r\n\r\n const res = await fetch(TOKEN_URL, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\r\n body: body.toString(),\r\n });\r\n\r\n if (!res.ok) {\r\n const text = await res.text();\r\n throw new AuthError(`Token refresh failed (${res.status}): ${text}`);\r\n }\r\n\r\n const data = (await res.json()) as {\r\n access_token: string;\r\n refresh_token?: string;\r\n expires_in: number | string;\r\n scope: string;\r\n };\r\n\r\n return {\r\n accessToken: data.access_token,\r\n refreshToken: data.refresh_token ?? refreshToken,\r\n expiresAt: Math.floor(Date.now() / 1000) + Number(data.expires_in),\r\n scope: data.scope,\r\n };\r\n}\r\n\r\n/**\r\n * Start OAuth callback server in background and return token when callback arrives.\r\n * Used by MCP tool to fire-and-forget while returning the auth URL immediately.\r\n */\r\nexport function startOAuthCallbackServer(\r\n clientId: string,\r\n clientSecret: string,\r\n): Promise<UserTokenResult> {\r\n return waitForAuthCode().then((code) =>\r\n exchangeCodeForToken(code, clientId, clientSecret)\r\n );\r\n}\r\n\r\nexport { REDIRECT_URI };\r\n","import { AuthError } from \"../utils/error.js\";\r\nimport { loadUserToken, saveUserToken } from \"./config.js\";\r\nimport { refreshUserToken } from \"./oauth-user.js\";\r\n\r\nexport async function getValidUserToken(profile = \"default\"): Promise<string> {\r\n const cached = await loadUserToken(profile);\r\n\r\n if (!cached) {\r\n throw new AuthError(\r\n \"User OAuth token not found. Run `nworks login --user` first.\"\r\n );\r\n }\r\n\r\n if (cached.expiresAt > Date.now() / 1000 + 300) {\r\n return cached.accessToken;\r\n }\r\n\r\n const refreshed = await refreshUserToken(cached.refreshToken, profile);\r\n await saveUserToken(refreshed, profile);\r\n return refreshed.accessToken;\r\n}\r\n","import { readFile, stat } from \"node:fs/promises\";\r\nimport { basename } from \"node:path\";\r\nimport { ApiError, AuthError } from \"../utils/error.js\";\r\nimport { getValidUserToken } from \"../auth/token-user.js\";\r\n\r\nconst BASE_URL = \"https://www.worksapis.com/v1.0\";\r\n\r\nexport interface DriveFile {\r\n fileId: string;\r\n parentFileId?: string;\r\n fileName: string;\r\n fileSize: number;\r\n filePath: string;\r\n fileType: string;\r\n createdTime: string;\r\n modifiedTime: string;\r\n accessedTime?: string;\r\n statuses?: string[];\r\n shared?: boolean;\r\n}\r\n\r\nexport interface FileListResult {\r\n files: DriveFile[];\r\n responseMetaData?: { nextCursor?: string };\r\n}\r\n\r\nexport interface UploadUrlResult {\r\n uploadUrl: string;\r\n offset: number;\r\n}\r\n\r\nexport interface UploadResult {\r\n fileId: string;\r\n fileName: string;\r\n fileSize: string;\r\n filePath: string;\r\n fileType: string;\r\n}\r\n\r\nasync function authedFetch(\r\n url: string,\r\n init: RequestInit,\r\n profile: string\r\n): Promise<Response> {\r\n const token = await getValidUserToken(profile);\r\n const headers = new Headers(init.headers);\r\n headers.set(\"Authorization\", `Bearer ${token}`);\r\n return fetch(url, { ...init, headers });\r\n}\r\n\r\nasync function handleError(res: Response): Promise<never> {\r\n if (res.status === 401) {\r\n throw new AuthError(\"User token expired. Run `nworks login --user --scope file` again.\");\r\n }\r\n let code = \"UNKNOWN\";\r\n let description = `HTTP ${res.status}`;\r\n try {\r\n const body = (await res.json()) as { code?: string; description?: string };\r\n code = body.code ?? code;\r\n description = body.description ?? description;\r\n } catch {\r\n // ignore\r\n }\r\n throw new ApiError(code, description, res.status);\r\n}\r\n\r\nexport async function listFiles(\r\n userId = \"me\",\r\n folderId?: string,\r\n count = 20,\r\n cursor?: string,\r\n profile = \"default\"\r\n): Promise<FileListResult> {\r\n const base = `${BASE_URL}/users/${userId}/drive/files`;\r\n const path = folderId ? `${base}/${folderId}/children` : base;\r\n\r\n const params = new URLSearchParams();\r\n params.set(\"count\", String(count));\r\n if (cursor) params.set(\"cursor\", cursor);\r\n\r\n const url = `${path}?${params.toString()}`;\r\n\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] GET ${url}`);\r\n }\r\n\r\n const res = await authedFetch(url, { method: \"GET\" }, profile);\r\n\r\n if (!res.ok) return handleError(res);\r\n\r\n const data = (await res.json()) as FileListResult;\r\n return { files: data.files ?? [], responseMetaData: data.responseMetaData };\r\n}\r\n\r\nexport async function uploadFile(\r\n localPath: string,\r\n userId = \"me\",\r\n folderId?: string,\r\n overwrite = false,\r\n profile = \"default\"\r\n): Promise<UploadResult> {\r\n const fileName = basename(localPath);\r\n const fileStat = await stat(localPath);\r\n const fileSize = fileStat.size;\r\n\r\n const base = `${BASE_URL}/users/${userId}/drive/files`;\r\n const createUrl = folderId ? `${base}/${folderId}` : base;\r\n\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] POST ${createUrl} (create upload URL)`);\r\n }\r\n\r\n const createRes = await authedFetch(\r\n createUrl,\r\n {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify({ fileName, fileSize, overwrite }),\r\n },\r\n profile\r\n );\r\n\r\n if (!createRes.ok) return handleError(createRes);\r\n\r\n const { uploadUrl } = (await createRes.json()) as UploadUrlResult;\r\n const fileBuffer = await readFile(localPath);\r\n const boundary = `----nworks${Date.now()}`;\r\n\r\n const header = Buffer.from(\r\n `--${boundary}\\r\\n` +\r\n `Content-Disposition: form-data; name=\"Filedata\"; filename=\"${fileName}\"\\r\\n` +\r\n `Content-Type: application/octet-stream\\r\\n\\r\\n`\r\n );\r\n const footer = Buffer.from(`\\r\\n--${boundary}--\\r\\n`);\r\n const body = Buffer.concat([header, fileBuffer, footer]);\r\n\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] POST ${uploadUrl} (upload content, ${fileSize} bytes)`);\r\n }\r\n\r\n const uploadRes = await authedFetch(\r\n uploadUrl,\r\n {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": `multipart/form-data; boundary=${boundary}` },\r\n body,\r\n },\r\n profile\r\n );\r\n\r\n if (!uploadRes.ok) return handleError(uploadRes);\r\n\r\n return (await uploadRes.json()) as UploadResult;\r\n}\r\n\r\nexport async function uploadBuffer(\r\n fileBuffer: Buffer,\r\n fileName: string,\r\n userId = \"me\",\r\n folderId?: string,\r\n overwrite = false,\r\n profile = \"default\"\r\n): Promise<UploadResult> {\r\n const fileSize = fileBuffer.length;\r\n\r\n const base = `${BASE_URL}/users/${userId}/drive/files`;\r\n const createUrl = folderId ? `${base}/${folderId}` : base;\r\n\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] POST ${createUrl} (create upload URL for buffer)`);\r\n }\r\n\r\n const createRes = await authedFetch(\r\n createUrl,\r\n {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify({ fileName, fileSize, overwrite }),\r\n },\r\n profile\r\n );\r\n\r\n if (!createRes.ok) return handleError(createRes);\r\n\r\n const { uploadUrl } = (await createRes.json()) as UploadUrlResult;\r\n const boundary = `----nworks${Date.now()}`;\r\n\r\n const header = Buffer.from(\r\n `--${boundary}\\r\\n` +\r\n `Content-Disposition: form-data; name=\"Filedata\"; filename=\"${fileName}\"\\r\\n` +\r\n `Content-Type: application/octet-stream\\r\\n\\r\\n`\r\n );\r\n const footer = Buffer.from(`\\r\\n--${boundary}--\\r\\n`);\r\n const body = Buffer.concat([header, fileBuffer, footer]);\r\n\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] POST ${uploadUrl} (upload buffer, ${fileSize} bytes)`);\r\n }\r\n\r\n const uploadRes = await authedFetch(\r\n uploadUrl,\r\n {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": `multipart/form-data; boundary=${boundary}` },\r\n body,\r\n },\r\n profile\r\n );\r\n\r\n if (!uploadRes.ok) return handleError(uploadRes);\r\n\r\n return (await uploadRes.json()) as UploadResult;\r\n}\r\n\r\nexport async function downloadFile(\r\n fileId: string,\r\n userId = \"me\",\r\n profile = \"default\"\r\n): Promise<{ buffer: Buffer; fileName?: string }> {\r\n const url = `${BASE_URL}/users/${userId}/drive/files/${fileId}/download`;\r\n\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] GET ${url} (get download URL)`);\r\n }\r\n\r\n const redirectRes = await authedFetch(\r\n url,\r\n { method: \"GET\", redirect: \"manual\" },\r\n profile\r\n );\r\n\r\n if (redirectRes.status === 401) {\r\n throw new AuthError(\"User token expired. Run `nworks login --user --scope file` again.\");\r\n }\r\n\r\n const location = redirectRes.headers.get(\"location\");\r\n if (!location) {\r\n if (!redirectRes.ok) return handleError(redirectRes);\r\n throw new ApiError(\"NO_REDIRECT\", \"No download URL returned\", redirectRes.status);\r\n }\r\n\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] GET ${location} (download content)`);\r\n }\r\n\r\n const downloadRes = await authedFetch(location, { method: \"GET\" }, profile);\r\n\r\n if (!downloadRes.ok) return handleError(downloadRes);\r\n\r\n const arrayBuffer = await downloadRes.arrayBuffer();\r\n const buffer = Buffer.from(arrayBuffer);\r\n\r\n const disposition = downloadRes.headers.get(\"content-disposition\");\r\n let fileName: string | undefined;\r\n if (disposition) {\r\n const match = disposition.match(/filename\\*?=(?:UTF-8''|\"?)([^\";]+)/i);\r\n if (match?.[1]) {\r\n fileName = decodeURIComponent(match[1].replace(/\"/g, \"\"));\r\n }\r\n }\r\n\r\n return { buffer, fileName };\r\n}\r\n","import { ApiError, AuthError } from \"../utils/error.js\";\r\nimport { getValidUserToken } from \"../auth/token-user.js\";\r\n\r\nconst BASE_URL = \"https://www.worksapis.com/v1.0\";\r\n\r\nexport interface MailAddress {\r\n name?: string;\r\n email: string;\r\n}\r\n\r\nexport interface SendMailOptions {\r\n to: string;\r\n cc?: string;\r\n bcc?: string;\r\n subject: string;\r\n body?: string;\r\n contentType?: \"html\" | \"text\";\r\n userId?: string;\r\n profile?: string;\r\n}\r\n\r\nexport interface MailSummary {\r\n mailId: number;\r\n folderId: number;\r\n status: string;\r\n from: MailAddress;\r\n to: MailAddress[];\r\n subject: string;\r\n receivedTime: string;\r\n sentTime?: string;\r\n size: number;\r\n isImportant?: boolean;\r\n attachCount?: number;\r\n}\r\n\r\nexport interface MailListResult {\r\n mails: MailSummary[];\r\n unreadCount?: number;\r\n folderName?: string;\r\n totalCount?: number;\r\n responseMetaData?: { nextCursor?: string };\r\n}\r\n\r\nexport interface MailDetail {\r\n mail: {\r\n mailId: number;\r\n folderId: number;\r\n status: number;\r\n from: MailAddress;\r\n to: MailAddress[];\r\n cc?: MailAddress[];\r\n bcc?: MailAddress[];\r\n subject: string;\r\n body: string;\r\n receivedTime: string;\r\n sentTime?: string;\r\n size: number;\r\n securityLevel?: string;\r\n };\r\n attachments?: Array<{\r\n attachmentId: number;\r\n contentType: string;\r\n filename: string;\r\n size: number;\r\n }>;\r\n}\r\n\r\nasync function authedFetch(\r\n url: string,\r\n init: RequestInit,\r\n profile: string\r\n): Promise<Response> {\r\n const token = await getValidUserToken(profile);\r\n const headers = new Headers(init.headers);\r\n headers.set(\"Authorization\", `Bearer ${token}`);\r\n return fetch(url, { ...init, headers });\r\n}\r\n\r\nasync function handleError(res: Response): Promise<never> {\r\n if (res.status === 401) {\r\n throw new AuthError(\"User token expired. Run `nworks login --user --scope mail` again.\");\r\n }\r\n let code = \"UNKNOWN\";\r\n let description = `HTTP ${res.status}`;\r\n try {\r\n const body = (await res.json()) as { code?: string; description?: string };\r\n code = body.code ?? code;\r\n description = body.description ?? description;\r\n } catch {\r\n // ignore\r\n }\r\n throw new ApiError(code, description, res.status);\r\n}\r\n\r\nexport async function sendMail(opts: SendMailOptions): Promise<void> {\r\n const userId = opts.userId ?? \"me\";\r\n const profile = opts.profile ?? \"default\";\r\n const url = `${BASE_URL}/users/${userId}/mail`;\r\n\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] POST ${url}`);\r\n }\r\n\r\n const body: Record<string, unknown> = {\r\n to: opts.to,\r\n subject: opts.subject,\r\n };\r\n if (opts.body !== undefined) body.body = opts.body;\r\n if (opts.cc) body.cc = opts.cc;\r\n if (opts.bcc) body.bcc = opts.bcc;\r\n if (opts.contentType) body.contentType = opts.contentType;\r\n\r\n const res = await authedFetch(\r\n url,\r\n {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify(body),\r\n },\r\n profile\r\n );\r\n\r\n if (res.status === 202) return;\r\n\r\n if (!res.ok) return handleError(res);\r\n}\r\n\r\nexport async function listMails(\r\n folderId = 0,\r\n userId = \"me\",\r\n count = 30,\r\n cursor?: string,\r\n isUnread?: boolean,\r\n profile = \"default\"\r\n): Promise<MailListResult> {\r\n const params = new URLSearchParams();\r\n params.set(\"count\", String(count));\r\n if (cursor) params.set(\"cursor\", cursor);\r\n if (isUnread) params.set(\"isUnread\", \"true\");\r\n\r\n const url = `${BASE_URL}/users/${userId}/mail/mailfolders/${folderId}/children?${params.toString()}`;\r\n\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] GET ${url}`);\r\n }\r\n\r\n const res = await authedFetch(url, { method: \"GET\" }, profile);\r\n\r\n if (!res.ok) return handleError(res);\r\n\r\n const data = (await res.json()) as MailListResult;\r\n return {\r\n mails: data.mails ?? [],\r\n unreadCount: data.unreadCount,\r\n folderName: data.folderName,\r\n totalCount: data.totalCount,\r\n responseMetaData: data.responseMetaData,\r\n };\r\n}\r\n\r\nexport async function readMail(\r\n mailId: number,\r\n userId = \"me\",\r\n profile = \"default\"\r\n): Promise<MailDetail> {\r\n const url = `${BASE_URL}/users/${userId}/mail/${mailId}`;\r\n\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] GET ${url}`);\r\n }\r\n\r\n const res = await authedFetch(url, { method: \"GET\" }, profile);\r\n\r\n if (!res.ok) return handleError(res);\r\n\r\n return (await res.json()) as MailDetail;\r\n}\r\n","import { ApiError, AuthError } from \"../utils/error.js\";\r\nimport { getValidUserToken } from \"../auth/token-user.js\";\r\n\r\nconst BASE_URL = \"https://www.worksapis.com/v1.0\";\r\n\r\nexport interface Assignee {\r\n assigneeId: string;\r\n assigneeName?: string;\r\n status: \"TODO\" | \"DONE\";\r\n}\r\n\r\nexport interface Task {\r\n taskId: string;\r\n title: string;\r\n content: string;\r\n status: \"TODO\" | \"DONE\";\r\n assignorId: string;\r\n assignorName?: string;\r\n assignees: Assignee[];\r\n completionCondition: \"ANY_ONE\" | \"MUST_ALL\";\r\n dueDate: string | null;\r\n createdTime: string;\r\n modifiedTime: string;\r\n}\r\n\r\nexport interface TaskListResult {\r\n tasks: Task[];\r\n responseMetaData?: { nextCursor?: string };\r\n}\r\n\r\nexport interface TaskCategory {\r\n categoryId: string;\r\n categoryName: string;\r\n}\r\n\r\nexport interface CreateTaskOptions {\r\n title: string;\r\n content?: string;\r\n dueDate?: string;\r\n categoryId?: string;\r\n assignorId?: string;\r\n assigneeIds?: string[];\r\n userId?: string;\r\n profile?: string;\r\n}\r\n\r\nexport interface UpdateTaskOptions {\r\n taskId: string;\r\n title?: string;\r\n content?: string;\r\n dueDate?: string | null;\r\n profile?: string;\r\n}\r\n\r\nasync function authedFetch(\r\n url: string,\r\n init: RequestInit,\r\n profile: string\r\n): Promise<Response> {\r\n const token = await getValidUserToken(profile);\r\n const headers = new Headers(init.headers);\r\n headers.set(\"Authorization\", `Bearer ${token}`);\r\n return fetch(url, { ...init, headers });\r\n}\r\n\r\nasync function handleError(res: Response): Promise<never> {\r\n if (res.status === 401) {\r\n throw new AuthError(\"User token expired. Run `nworks login --user --scope task` again.\");\r\n }\r\n let code = \"UNKNOWN\";\r\n let description = `HTTP ${res.status}`;\r\n try {\r\n const body = (await res.json()) as { code?: string; description?: string };\r\n code = body.code ?? code;\r\n description = body.description ?? description;\r\n } catch {\r\n // ignore\r\n }\r\n throw new ApiError(code, description, res.status);\r\n}\r\n\r\nasync function resolveUserId(\r\n userId: string,\r\n profile: string\r\n): Promise<string> {\r\n if (userId !== \"me\") return userId;\r\n\r\n const url = `${BASE_URL}/users/me`;\r\n const res = await authedFetch(url, { method: \"GET\" }, profile);\r\n if (!res.ok) return handleError(res);\r\n\r\n const data = (await res.json()) as { userId: string };\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] Resolved \"me\" → ${data.userId}`);\r\n }\r\n return data.userId;\r\n}\r\n\r\nexport async function listCategories(\r\n userId = \"me\",\r\n profile = \"default\"\r\n): Promise<TaskCategory[]> {\r\n const url = `${BASE_URL}/users/${userId}/task-categories`;\r\n\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] GET ${url}`);\r\n }\r\n\r\n const res = await authedFetch(url, { method: \"GET\" }, profile);\r\n if (!res.ok) return handleError(res);\r\n\r\n const data = (await res.json()) as { taskCategories: TaskCategory[] };\r\n return data.taskCategories ?? [];\r\n}\r\n\r\nexport async function listTasks(\r\n categoryId = \"default\",\r\n userId = \"me\",\r\n count = 50,\r\n cursor?: string,\r\n status: \"TODO\" | \"ALL\" = \"ALL\",\r\n profile = \"default\"\r\n): Promise<TaskListResult> {\r\n const params = new URLSearchParams();\r\n params.set(\"categoryId\", categoryId);\r\n params.set(\"count\", String(count));\r\n params.set(\"status\", status);\r\n if (cursor) params.set(\"cursor\", cursor);\r\n\r\n const url = `${BASE_URL}/users/${userId}/tasks?${params.toString()}`;\r\n\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] GET ${url}`);\r\n }\r\n\r\n const res = await authedFetch(url, { method: \"GET\" }, profile);\r\n if (!res.ok) return handleError(res);\r\n\r\n const data = (await res.json()) as TaskListResult;\r\n return { tasks: data.tasks ?? [], responseMetaData: data.responseMetaData };\r\n}\r\n\r\nexport async function getTask(\r\n taskId: string,\r\n profile = \"default\"\r\n): Promise<Task> {\r\n const url = `${BASE_URL}/tasks/${taskId}`;\r\n\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] GET ${url}`);\r\n }\r\n\r\n const res = await authedFetch(url, { method: \"GET\" }, profile);\r\n if (!res.ok) return handleError(res);\r\n\r\n return (await res.json()) as Task;\r\n}\r\n\r\nexport async function createTask(opts: CreateTaskOptions): Promise<Task> {\r\n const userId = opts.userId ?? \"me\";\r\n const profile = opts.profile ?? \"default\";\r\n\r\n const resolvedUserId = await resolveUserId(userId, profile);\r\n const assignorId = opts.assignorId ?? resolvedUserId;\r\n const assigneeIds = opts.assigneeIds ?? [resolvedUserId];\r\n\r\n const body: Record<string, unknown> = {\r\n assignorId,\r\n assignees: assigneeIds.map((id) => ({ assigneeId: id, status: \"TODO\" })),\r\n title: opts.title,\r\n content: opts.content ?? \"\",\r\n completionCondition: \"ANY_ONE\",\r\n };\r\n if (opts.dueDate) body.dueDate = opts.dueDate;\r\n if (opts.categoryId) body.categoryId = opts.categoryId;\r\n\r\n const url = `${BASE_URL}/users/${userId}/tasks`;\r\n\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] POST ${url}`);\r\n console.error(`[nworks] Body: ${JSON.stringify(body, null, 2)}`);\r\n }\r\n\r\n const res = await authedFetch(\r\n url,\r\n {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify(body),\r\n },\r\n profile\r\n );\r\n\r\n if (res.status === 201) {\r\n return (await res.json()) as Task;\r\n }\r\n if (!res.ok) return handleError(res);\r\n return (await res.json()) as Task;\r\n}\r\n\r\nexport async function updateTask(opts: UpdateTaskOptions): Promise<Task> {\r\n const profile = opts.profile ?? \"default\";\r\n\r\n const body: Record<string, unknown> = {};\r\n if (opts.title !== undefined) body.title = opts.title;\r\n if (opts.content !== undefined) body.content = opts.content;\r\n if (opts.dueDate !== undefined) body.dueDate = opts.dueDate;\r\n\r\n const url = `${BASE_URL}/tasks/${opts.taskId}`;\r\n\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] PATCH ${url}`);\r\n }\r\n\r\n const res = await authedFetch(\r\n url,\r\n {\r\n method: \"PATCH\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify(body),\r\n },\r\n profile\r\n );\r\n\r\n if (!res.ok) return handleError(res);\r\n return (await res.json()) as Task;\r\n}\r\n\r\nexport async function completeTask(\r\n taskId: string,\r\n profile = \"default\"\r\n): Promise<void> {\r\n const url = `${BASE_URL}/tasks/${taskId}/complete`;\r\n\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] POST ${url}`);\r\n }\r\n\r\n const res = await authedFetch(\r\n url,\r\n { method: \"POST\" },\r\n profile\r\n );\r\n\r\n if (res.status === 204) return;\r\n if (!res.ok) return handleError(res);\r\n}\r\n\r\nexport async function incompleteTask(\r\n taskId: string,\r\n profile = \"default\"\r\n): Promise<void> {\r\n const url = `${BASE_URL}/tasks/${taskId}/incomplete`;\r\n\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] POST ${url}`);\r\n }\r\n\r\n const res = await authedFetch(\r\n url,\r\n { method: \"POST\" },\r\n profile\r\n );\r\n\r\n if (res.status === 204) return;\r\n if (!res.ok) return handleError(res);\r\n}\r\n\r\nexport async function deleteTask(\r\n taskId: string,\r\n profile = \"default\"\r\n): Promise<void> {\r\n const url = `${BASE_URL}/tasks/${taskId}`;\r\n\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] DELETE ${url}`);\r\n }\r\n\r\n const res = await authedFetch(\r\n url,\r\n { method: \"DELETE\" },\r\n profile\r\n );\r\n\r\n if (res.status === 204) return;\r\n if (!res.ok) return handleError(res);\r\n}\r\n","import { ApiError, AuthError } from \"../utils/error.js\";\r\nimport { getValidUserToken } from \"../auth/token-user.js\";\r\n\r\nconst BASE_URL = \"https://www.worksapis.com/v1.0\";\r\n\r\nexport interface Board {\r\n boardId: string;\r\n boardName: string;\r\n description?: string;\r\n createdTime?: string;\r\n domainId?: string;\r\n}\r\n\r\nexport interface BoardListResult {\r\n boards: Board[];\r\n responseMetaData?: { nextCursor?: string };\r\n}\r\n\r\nexport interface Post {\r\n boardId: string;\r\n postId: string;\r\n title: string;\r\n body?: string;\r\n readCount?: number;\r\n userName?: string;\r\n userId?: string;\r\n createdTime?: string;\r\n updatedTime?: string;\r\n commentCount?: number;\r\n enableComment?: boolean;\r\n}\r\n\r\nexport interface PostListResult {\r\n posts: Post[];\r\n responseMetaData?: { nextCursor?: string };\r\n}\r\n\r\nexport interface CreatePostOptions {\r\n boardId: string;\r\n title: string;\r\n body?: string;\r\n enableComment?: boolean;\r\n sendNotifications?: boolean;\r\n profile?: string;\r\n}\r\n\r\nasync function authedFetch(\r\n url: string,\r\n init: RequestInit,\r\n profile: string\r\n): Promise<Response> {\r\n const token = await getValidUserToken(profile);\r\n const headers = new Headers(init.headers);\r\n headers.set(\"Authorization\", `Bearer ${token}`);\r\n return fetch(url, { ...init, headers });\r\n}\r\n\r\nasync function handleError(res: Response): Promise<never> {\r\n if (res.status === 401) {\r\n throw new AuthError(\"User token expired. Run `nworks login --user --scope board` again.\");\r\n }\r\n let code = \"UNKNOWN\";\r\n let description = `HTTP ${res.status}`;\r\n try {\r\n const body = (await res.json()) as { code?: string; description?: string };\r\n code = body.code ?? code;\r\n description = body.description ?? description;\r\n } catch {\r\n // ignore\r\n }\r\n throw new ApiError(code, description, res.status);\r\n}\r\n\r\n/** int64 ID 필드의 정밀도 손실 방지를 위해 문자열로 변환 후 파싱 */\r\nfunction safeParseJson<T>(text: string): T {\r\n const safe = text.replace(\r\n /\"((?:board|post|domain|user)Id)\"\\s*:\\s*(\\d{16,})/g,\r\n '\"$1\":\"$2\"'\r\n );\r\n return JSON.parse(safe) as T;\r\n}\r\n\r\nexport async function listBoards(\r\n count = 20,\r\n cursor?: string,\r\n profile = \"default\"\r\n): Promise<BoardListResult> {\r\n const params = new URLSearchParams();\r\n params.set(\"count\", String(count));\r\n if (cursor) params.set(\"cursor\", cursor);\r\n\r\n const url = `${BASE_URL}/boards?${params.toString()}`;\r\n\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] GET ${url}`);\r\n }\r\n\r\n const res = await authedFetch(url, { method: \"GET\" }, profile);\r\n if (!res.ok) return handleError(res);\r\n\r\n const text = await res.text();\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] Response: ${text}`);\r\n }\r\n\r\n const data = safeParseJson<BoardListResult>(text);\r\n return { boards: data.boards ?? [], responseMetaData: data.responseMetaData };\r\n}\r\n\r\nexport async function listPosts(\r\n boardId: string,\r\n count = 20,\r\n cursor?: string,\r\n profile = \"default\"\r\n): Promise<PostListResult> {\r\n const params = new URLSearchParams();\r\n params.set(\"count\", String(count));\r\n if (cursor) params.set(\"cursor\", cursor);\r\n\r\n const url = `${BASE_URL}/boards/${boardId}/posts?${params.toString()}`;\r\n\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] GET ${url}`);\r\n }\r\n\r\n const res = await authedFetch(url, { method: \"GET\" }, profile);\r\n if (!res.ok) return handleError(res);\r\n\r\n const text = await res.text();\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] Response: ${text}`);\r\n }\r\n\r\n const data = safeParseJson<PostListResult>(text);\r\n return { posts: data.posts ?? [], responseMetaData: data.responseMetaData };\r\n}\r\n\r\nexport async function readPost(\r\n boardId: string,\r\n postId: string,\r\n profile = \"default\"\r\n): Promise<Post> {\r\n const url = `${BASE_URL}/boards/${boardId}/posts/${postId}`;\r\n\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] GET ${url}`);\r\n }\r\n\r\n const res = await authedFetch(url, { method: \"GET\" }, profile);\r\n if (!res.ok) return handleError(res);\r\n\r\n const text = await res.text();\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] Response: ${text}`);\r\n }\r\n\r\n return safeParseJson<Post>(text);\r\n}\r\n\r\nexport async function createPost(opts: CreatePostOptions): Promise<Post> {\r\n const profile = opts.profile ?? \"default\";\r\n\r\n const body: Record<string, unknown> = {\r\n title: opts.title,\r\n body: opts.body ?? \"\",\r\n };\r\n if (opts.enableComment !== undefined) body.enableComment = opts.enableComment;\r\n if (opts.sendNotifications !== undefined) body.sendNotifications = opts.sendNotifications;\r\n\r\n const url = `${BASE_URL}/boards/${opts.boardId}/posts`;\r\n\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] POST ${url}`);\r\n console.error(`[nworks] Body: ${JSON.stringify(body, null, 2)}`);\r\n }\r\n\r\n const res = await authedFetch(\r\n url,\r\n {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify(body),\r\n },\r\n profile\r\n );\r\n\r\n if (res.status === 201 || res.ok) {\r\n const text = await res.text();\r\n if (process.env[\"NWORKS_VERBOSE\"] === \"1\") {\r\n console.error(`[nworks] Response: ${text}`);\r\n }\r\n return safeParseJson<Post>(text);\r\n }\r\n return handleError(res);\r\n}\r\n","import { Command } from \"commander\";\r\nimport { existsSync } from \"node:fs\";\r\nimport { readFile } from \"node:fs/promises\";\r\nimport { loadCredentials, loadToken, loadUserToken, hasServiceAccountCreds } from \"../auth/config.js\";\r\nimport { output } from \"../output/format.js\";\r\nimport { cliError } from \"../output/cli-error.js\";\r\n\r\ninterface CheckResult {\r\n check: string;\r\n status: string;\r\n detail: string;\r\n}\r\n\r\nasync function runChecks(profile: string): Promise<CheckResult[]> {\r\n const results: CheckResult[] = [];\r\n\r\n // 1. Credentials\r\n let creds;\r\n try {\r\n creds = await loadCredentials(profile);\r\n results.push({ check: \"credentials\", status: \"OK\", detail: `clientId: ${creds.clientId}` });\r\n } catch {\r\n results.push({ check: \"credentials\", status: \"FAIL\", detail: \"인증 정보 없음. `nworks login` 또는 nworks_setup 필요\" });\r\n return results;\r\n }\r\n\r\n // 2. Service Account\r\n if (hasServiceAccountCreds(creds)) {\r\n results.push({ check: \"serviceAccount\", status: \"OK\", detail: creds.serviceAccount });\r\n } else {\r\n results.push({ check: \"serviceAccount\", status: \"SKIP\", detail: \"미설정 (봇 메시지 사용 시 필요)\" });\r\n }\r\n\r\n // 3. Private Key file\r\n if (creds.privateKeyPath) {\r\n if (existsSync(creds.privateKeyPath)) {\r\n try {\r\n await readFile(creds.privateKeyPath, \"utf-8\");\r\n results.push({ check: \"privateKey\", status: \"OK\", detail: creds.privateKeyPath });\r\n } catch {\r\n results.push({ check: \"privateKey\", status: \"FAIL\", detail: `읽기 불가: ${creds.privateKeyPath}` });\r\n }\r\n } else {\r\n results.push({ check: \"privateKey\", status: \"FAIL\", detail: `파일 없음: ${creds.privateKeyPath}` });\r\n }\r\n } else {\r\n results.push({ check: \"privateKey\", status: \"SKIP\", detail: \"미설정\" });\r\n }\r\n\r\n // 4. Bot ID\r\n if (creds.botId) {\r\n results.push({ check: \"botId\", status: \"OK\", detail: creds.botId });\r\n } else {\r\n results.push({ check: \"botId\", status: \"SKIP\", detail: \"미설정 (메시지 전송 시 필요)\" });\r\n }\r\n\r\n // 5. Service Account Token\r\n const token = await loadToken(profile);\r\n if (token) {\r\n const valid = token.expiresAt > Date.now() / 1000;\r\n results.push({\r\n check: \"serviceToken\",\r\n status: valid ? \"OK\" : \"EXPIRED\",\r\n detail: valid\r\n ? `만료: ${new Date(token.expiresAt * 1000).toISOString()}`\r\n : `만료됨: ${new Date(token.expiresAt * 1000).toISOString()}`,\r\n });\r\n } else {\r\n results.push({ check: \"serviceToken\", status: \"SKIP\", detail: \"토큰 없음\" });\r\n }\r\n\r\n // 6. User OAuth Token\r\n const userToken = await loadUserToken(profile);\r\n if (userToken) {\r\n const valid = userToken.expiresAt > Date.now() / 1000;\r\n results.push({\r\n check: \"userOAuth\",\r\n status: valid ? \"OK\" : \"EXPIRED\",\r\n detail: valid\r\n ? `scope: ${userToken.scope} | 만료: ${new Date(userToken.expiresAt * 1000).toISOString()}`\r\n : `만료됨 | scope: ${userToken.scope}`,\r\n });\r\n } else {\r\n results.push({ check: \"userOAuth\", status: \"SKIP\", detail: \"토큰 없음. `nworks login --user` 필요\" });\r\n }\r\n\r\n // 7. API connectivity test\r\n if (hasServiceAccountCreds(creds) && token && token.expiresAt > Date.now() / 1000) {\r\n try {\r\n const res = await fetch(\"https://www.worksapis.com/v1.0/users/me\", {\r\n headers: { Authorization: `Bearer ${token.accessToken}` },\r\n });\r\n if (res.ok) {\r\n results.push({ check: \"apiConnection\", status: \"OK\", detail: \"NAVER WORKS API 연결 성공\" });\r\n } else {\r\n results.push({ check: \"apiConnection\", status: \"FAIL\", detail: `HTTP ${res.status}` });\r\n }\r\n } catch (e) {\r\n results.push({ check: \"apiConnection\", status: \"FAIL\", detail: `연결 실패: ${(e as Error).message}` });\r\n }\r\n } else if (userToken && userToken.expiresAt > Date.now() / 1000) {\r\n try {\r\n const res = await fetch(\"https://www.worksapis.com/v1.0/users/me\", {\r\n headers: { Authorization: `Bearer ${userToken.accessToken}` },\r\n });\r\n if (res.ok) {\r\n results.push({ check: \"apiConnection\", status: \"OK\", detail: \"NAVER WORKS API 연결 성공\" });\r\n } else {\r\n results.push({ check: \"apiConnection\", status: \"FAIL\", detail: `HTTP ${res.status}` });\r\n }\r\n } catch (e) {\r\n results.push({ check: \"apiConnection\", status: \"FAIL\", detail: `연결 실패: ${(e as Error).message}` });\r\n }\r\n } else {\r\n results.push({ check: \"apiConnection\", status: \"SKIP\", detail: \"유효한 토큰 없음 — API 테스트 건너뜀\" });\r\n }\r\n\r\n return results;\r\n}\r\n\r\nexport { runChecks };\r\n\r\nexport const doctorCommand = new Command(\"doctor\")\r\n .description(\"Check nworks configuration and connectivity\")\r\n .option(\"--profile <name>\", \"Profile name\", \"default\")\r\n .option(\"--json\", \"JSON output\")\r\n .action(async (opts) => {\r\n try {\r\n const results = await runChecks(opts.profile as string);\r\n\r\n if (opts.json || !process.stdout.isTTY) {\r\n output(results, opts);\r\n } else {\r\n console.log(\"\\n nworks doctor\\n\");\r\n for (const r of results) {\r\n const icon = r.status === \"OK\" ? \"\\u2705\" : r.status === \"SKIP\" ? \"\\u2796\" : \"\\u274C\";\r\n console.log(` ${icon} ${r.check.padEnd(16)} ${r.detail}`);\r\n }\r\n console.log();\r\n }\r\n } catch (err) {\r\n cliError(err, opts);\r\n }\r\n });\r\n","interface FormatOptions {\r\n json?: boolean;\r\n}\r\n\r\nexport function output(data: unknown, opts: FormatOptions = {}): void {\r\n const useJson = opts.json || !process.stdout.isTTY;\r\n\r\n if (useJson) {\r\n console.log(JSON.stringify(data, null, 2));\r\n return;\r\n }\r\n\r\n if (Array.isArray(data)) {\r\n printTable(data);\r\n } else if (typeof data === \"object\" && data !== null) {\r\n const record = data as Record<string, unknown>;\r\n for (const value of Object.values(record)) {\r\n if (Array.isArray(value) && value.length > 0) {\r\n printTable(value);\r\n return;\r\n }\r\n }\r\n for (const [key, value] of Object.entries(record)) {\r\n console.log(` ${key}: ${String(value)}`);\r\n }\r\n } else {\r\n console.log(String(data));\r\n }\r\n}\r\n\r\nfunction printTable(rows: unknown[]): void {\r\n if (rows.length === 0) {\r\n console.log(\" (no data)\");\r\n return;\r\n }\r\n\r\n const first = rows[0] as Record<string, unknown>;\r\n const keys = Object.keys(first);\r\n\r\n const widths: Record<string, number> = {};\r\n for (const key of keys) {\r\n widths[key] = key.length;\r\n }\r\n for (const row of rows) {\r\n const record = row as Record<string, unknown>;\r\n for (const key of keys) {\r\n const len = String(record[key] ?? \"\").length;\r\n if (len > (widths[key] ?? 0)) {\r\n widths[key] = len;\r\n }\r\n }\r\n }\r\n\r\n const header = keys.map((k) => k.padEnd(widths[k] ?? 0)).join(\" \");\r\n const separator = keys.map((k) => \"─\".repeat(widths[k] ?? 0)).join(\"──\");\r\n\r\n console.log(` ${header}`);\r\n console.log(` ${separator}`);\r\n\r\n for (const row of rows) {\r\n const record = row as Record<string, unknown>;\r\n const line = keys\r\n .map((k) => String(record[k] ?? \"\").padEnd(widths[k] ?? 0))\r\n .join(\" \");\r\n console.log(` ${line}`);\r\n }\r\n}\r\n\r\nexport function errorOutput(\r\n error: { code?: string; message: string; hint?: string },\r\n opts: FormatOptions = {}\r\n): void {\r\n const payload = {\r\n success: false,\r\n error: { code: error.code ?? \"ERROR\", message: error.message, hint: error.hint },\r\n };\r\n\r\n if (opts.json || !process.stderr.isTTY) {\r\n console.error(JSON.stringify(payload, null, 2));\r\n } else {\r\n console.error(` Error: ${error.message}`);\r\n if (error.code) {\r\n console.error(` Code: ${error.code}`);\r\n }\r\n if (error.hint) {\r\n console.error(` → ${error.hint}`);\r\n }\r\n }\r\n}\r\n","import { ApiError, AuthError } from \"./error.js\";\r\n\r\n/** Scope required by each command/API area */\r\nexport const REQUIRED_SCOPES: Record<string, string> = {\r\n calendar: \"calendar\",\r\n \"calendar.list\": \"calendar.read\",\r\n \"calendar.create\": \"calendar calendar.read\",\r\n \"calendar.update\": \"calendar calendar.read\",\r\n \"calendar.delete\": \"calendar calendar.read\",\r\n mail: \"mail\",\r\n \"mail.send\": \"mail\",\r\n \"mail.list\": \"mail.read\",\r\n \"mail.read\": \"mail.read\",\r\n task: \"task\",\r\n \"task.list\": \"task.read\",\r\n \"task.create\": \"task user.read\",\r\n \"task.update\": \"task user.read\",\r\n \"task.delete\": \"task user.read\",\r\n drive: \"file\",\r\n \"drive.list\": \"file.read\",\r\n \"drive.upload\": \"file\",\r\n \"drive.download\": \"file.read\",\r\n board: \"board\",\r\n \"board.list\": \"board.read\",\r\n \"board.posts\": \"board.read\",\r\n \"board.read\": \"board.read\",\r\n \"board.create\": \"board\",\r\n};\r\n\r\nconst ERROR_HINTS_CLI: Record<string, string> = {\r\n FORBIDDEN: \"권한이 부족합니다. Developer Console에서 OAuth Scope를 확인하세요.\",\r\n ACCESS_DENIED: \"접근이 거부됐습니다. Admin에서 Bot을 추가했는지 확인하세요.\",\r\n SERVICE_ACCOUNT_NOT_ALLOWED:\r\n \"서비스 계정으로는 이 API를 사용할 수 없습니다. `nworks login --user`로 User OAuth 로그인하세요.\",\r\n UNAUTHORIZED: \"인증이 만료됐습니다. `nworks login`으로 다시 로그인하세요.\",\r\n};\r\n\r\nconst ERROR_HINTS_MCP: Record<string, string> = {\r\n FORBIDDEN: \"권한이 부족합니다. Developer Console에서 OAuth Scope를 확인하세요.\",\r\n ACCESS_DENIED: \"접근이 거부됐습니다. Admin에서 Bot을 추가했는지 확인하세요.\",\r\n SERVICE_ACCOUNT_NOT_ALLOWED:\r\n \"서비스 계정으로는 이 API를 사용할 수 없습니다. nworks_login_user tool로 User OAuth 로그인을 먼저 해주세요.\",\r\n UNAUTHORIZED: \"인증이 만료됐습니다. nworks_setup tool로 재설정하세요.\",\r\n};\r\n\r\n/**\r\n * Build a user-friendly hint string for CLI error output.\r\n * @param err The thrown error\r\n * @param area Optional command area (e.g. \"calendar.list\") to suggest the exact scope\r\n */\r\nexport function cliErrorHint(err: unknown, area?: string): string {\r\n if (err instanceof ApiError) {\r\n const hint = ERROR_HINTS_CLI[err.code];\r\n const scopeHint = area ? buildScopeHint(area, \"cli\") : \"\";\r\n if (hint) {\r\n return `[${err.code}] ${err.message}\\n → ${hint}${scopeHint}`;\r\n }\r\n return `[${err.code}] ${err.message}${scopeHint}`;\r\n }\r\n if (err instanceof AuthError) {\r\n return `${err.message}\\n → ${ERROR_HINTS_CLI[\"UNAUTHORIZED\"]}`;\r\n }\r\n return (err as Error).message;\r\n}\r\n\r\n/**\r\n * Build a user-friendly hint string for MCP tool error output.\r\n */\r\nexport function mcpErrorHint(err: unknown, area?: string): string {\r\n if (err instanceof ApiError) {\r\n const hint = ERROR_HINTS_MCP[err.code];\r\n const scopeHint = area ? buildScopeHint(area, \"mcp\") : \"\";\r\n if (hint) {\r\n return `Error: [${err.code}] ${err.message}\\n\\n[안내] ${hint}${scopeHint}`;\r\n }\r\n return `Error: [${err.code}] ${err.message}${scopeHint}`;\r\n }\r\n if (err instanceof AuthError) {\r\n return `Error: ${err.message}\\n\\n[안내] 인증 정보가 없습니다. nworks_setup tool로 Client ID/Secret을 먼저 설정해주세요.`;\r\n }\r\n return `Error: ${(err as Error).message}`;\r\n}\r\n\r\nfunction buildScopeHint(area: string, mode: \"cli\" | \"mcp\"): string {\r\n const scope = REQUIRED_SCOPES[area];\r\n if (!scope) return \"\";\r\n const scopes = scope.split(\" \").join(\", \");\r\n if (mode === \"cli\") {\r\n return `\\n → 이 명령어는 ${scopes} scope가 필요합니다. \\`nworks login --user --scope \"${scope}\"\\`를 실행하세요.`;\r\n }\r\n return `\\n → 이 API는 ${scopes} scope가 필요합니다. nworks_login_user tool로 로그인하세요 (scope를 지정하지 않으면 전체 권한이 자동 포함됩니다).`;\r\n}\r\n","import { ApiError, AuthError } from \"../utils/error.js\";\r\nimport { cliErrorHint } from \"../utils/error-hints.js\";\r\nimport { errorOutput } from \"./format.js\";\r\n\r\n/**\r\n * Standard CLI error handler with Korean hints.\r\n * Use in command catch blocks: `cliError(err, opts, \"calendar.list\")`\r\n */\r\nexport function cliError(\r\n err: unknown,\r\n opts: { json?: boolean } = {},\r\n area?: string,\r\n): void {\r\n const error = err as Error;\r\n\r\n if (error instanceof ApiError) {\r\n errorOutput(\r\n {\r\n code: error.code,\r\n message: error.message,\r\n hint: cliErrorHint(err, area).split(\"\\n\").slice(1).map((l) => l.replace(/^\\s+→\\s*/, \"\")).join(\" \"),\r\n },\r\n opts,\r\n );\r\n } else if (error instanceof AuthError) {\r\n errorOutput(\r\n {\r\n code: \"AUTH_ERROR\",\r\n message: error.message,\r\n hint: \"인증이 만료됐습니다. `nworks login`으로 다시 로그인하세요.\",\r\n },\r\n opts,\r\n );\r\n } else {\r\n errorOutput({ message: error.message }, opts);\r\n }\r\n\r\n process.exitCode = 1;\r\n}\r\n","import { startMcpServer } from \"./mcp/server.js\";\r\n\r\nstartMcpServer().catch((err) => {\r\n console.error(\"MCP server failed:\", err);\r\n process.exit(1);\r\n});\r\n"],"mappings":"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","names":["readFile","readFile","AUTH_URL","refreshToken","BASE_URL","readFile","BASE_URL","authedFetch","handleError","readFile","BASE_URL","authedFetch","handleError","BASE_URL","authedFetch","handleError","BASE_URL","authedFetch","handleError","BASE_URL","authedFetch","handleError","BASE_URL","authedFetch","handleError","existsSync","readFile","existsSync","readFile","writeFile","join"]}