nworks 1.2.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +38 -20
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +33 -19
- package/dist/mcp.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/commands/login.ts","../src/auth/config.ts","../src/utils/error.ts","../src/auth/jwt.ts","../src/auth/token.ts","../src/auth/oauth-user.ts","../src/output/format.ts","../src/commands/logout.ts","../src/utils/error-hints.ts","../src/output/cli-error.ts","../src/commands/whoami.ts","../src/commands/message.ts","../src/api/client.ts","../src/api/message.ts","../src/commands/directory.ts","../src/api/directory.ts","../src/commands/calendar.ts","../src/api/calendar.ts","../src/auth/token-user.ts","../src/commands/drive.ts","../src/api/drive.ts","../src/commands/mail.ts","../src/api/mail.ts","../src/commands/task.ts","../src/api/task.ts","../src/commands/board.ts","../src/api/board.ts","../src/commands/mcp-cmd.ts","../src/mcp/server.ts","../src/mcp/tools.ts","../src/commands/doctor.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\r\nimport { Command } from \"commander\";\r\nimport { loginCommand } from \"./commands/login.js\";\r\nimport { logoutCommand } from \"./commands/logout.js\";\r\nimport { whoamiCommand } from \"./commands/whoami.js\";\r\nimport { messageCommand } from \"./commands/message.js\";\r\nimport { directoryCommand } from \"./commands/directory.js\";\r\nimport { calendarCommand } from \"./commands/calendar.js\";\r\nimport { driveCommand } from \"./commands/drive.js\";\r\nimport { mailCommand } from \"./commands/mail.js\";\r\nimport { taskCommand } from \"./commands/task.js\";\r\nimport { boardCommand } from \"./commands/board.js\";\r\nimport { mcpCommand } from \"./commands/mcp-cmd.js\";\r\nimport { doctorCommand } from \"./commands/doctor.js\";\r\n\r\nconst require = createRequire(import.meta.url);\r\nconst { version } = require(\"../package.json\") as { version: string };\r\n\r\nconst program = new Command()\r\n .name(\"nworks\")\r\n .description(\"NAVER WORKS CLI — built for humans and AI agents\")\r\n .version(version)\r\n .option(\"--json\", \"Always output JSON\")\r\n .option(\"-v, --verbose\", \"Debug logging\")\r\n .option(\"--dry-run\", \"Print request without calling API\")\r\n .option(\"-p, --profile <name>\", \"Profile name\", \"default\");\r\n\r\nprogram.addCommand(loginCommand);\r\nprogram.addCommand(logoutCommand);\r\nprogram.addCommand(whoamiCommand);\r\nprogram.addCommand(messageCommand);\r\nprogram.addCommand(directoryCommand);\r\nprogram.addCommand(calendarCommand);\r\nprogram.addCommand(driveCommand);\r\nprogram.addCommand(mailCommand);\r\nprogram.addCommand(taskCommand);\r\nprogram.addCommand(boardCommand);\r\nprogram.addCommand(mcpCommand);\r\nprogram.addCommand(doctorCommand);\r\n\r\nprogram.parse();\r\n","import { Command } from \"commander\";\r\nimport { readFile } from \"node:fs/promises\";\r\nimport { existsSync } from \"node:fs\";\r\nimport { createInterface } from \"node:readline/promises\";\r\nimport { saveCredentials, saveUserToken, loadCredentials, type Credentials } from \"../auth/config.js\";\r\nimport { refreshToken } from \"../auth/token.js\";\r\nimport { startUserOAuthFlow, buildAuthorizeUrl } from \"../auth/oauth-user.js\";\r\nimport { output, errorOutput } from \"../output/format.js\";\r\nimport { randomBytes } from \"node:crypto\";\r\n\r\nasync function prompt(question: string): Promise<string> {\r\n const rl = createInterface({\r\n input: process.stdin,\r\n output: process.stdout,\r\n });\r\n try {\r\n const answer = await rl.question(question);\r\n return answer.trim();\r\n } finally {\r\n rl.close();\r\n }\r\n}\r\n\r\nexport const loginCommand = new Command(\"login\")\r\n .description(\"Authenticate with NAVER WORKS\")\r\n .option(\"--user\", \"User OAuth login (opens browser)\")\r\n .option(\"--scope <scope>\", \"OAuth scope for user login\", \"calendar.read\")\r\n .option(\"--client-id <id>\", \"Client ID\")\r\n .option(\"--client-secret <secret>\", \"Client Secret\")\r\n .option(\"--service-account <account>\", \"Service Account ID\")\r\n .option(\"--private-key <path>\", \"Path to private key file (.key)\")\r\n .option(\"--bot-id <id>\", \"Bot ID\")\r\n .option(\"--domain-id <id>\", \"Domain ID (optional)\")\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 profile = opts.profile as string;\r\n\r\n if (opts.user) {\r\n await handleUserLogin(opts.scope as string, profile, opts);\r\n } else {\r\n await handleServiceAccountLogin(opts);\r\n }\r\n } catch (err) {\r\n const error = err as Error;\r\n errorOutput({ message: error.message }, opts);\r\n process.exitCode = 1;\r\n }\r\n });\r\n\r\nasync function handleUserLogin(\r\n scope: string,\r\n profile: string,\r\n opts: Record<string, unknown>\r\n): Promise<void> {\r\n let clientId = opts.clientId as string | undefined;\r\n let clientSecret = opts.clientSecret as string | undefined;\r\n\r\n try {\r\n const existing = await loadCredentials(profile);\r\n if (!clientId) clientId = existing.clientId;\r\n if (!clientSecret) clientSecret = existing.clientSecret;\r\n } catch {\r\n // ignore\r\n }\r\n\r\n if (process.stdin.isTTY) {\r\n if (!clientId) clientId = await prompt(\"Client ID: \");\r\n if (!clientSecret) clientSecret = await prompt(\"Client Secret: \");\r\n }\r\n\r\n if (!clientId || !clientSecret) {\r\n throw new Error(\r\n \"Client ID and Client Secret are required for User OAuth.\\n\" +\r\n \"Use --client-id and --client-secret flags, or set NWORKS_CLIENT_ID / NWORKS_CLIENT_SECRET env vars.\"\r\n );\r\n }\r\n\r\n try {\r\n const existing = await loadCredentials(profile);\r\n await saveCredentials({ ...existing, clientId, clientSecret }, profile);\r\n } catch {\r\n await saveCredentials({ clientId, clientSecret }, profile);\r\n }\r\n\r\n const state = randomBytes(16).toString(\"hex\");\r\n const authorizeUrl = buildAuthorizeUrl(clientId, scope, state);\r\n\r\n console.error(`\\nOpening browser for NAVER WORKS login...`);\r\n console.error(`If the browser does not open, visit this URL:\\n`);\r\n console.error(` ${authorizeUrl}\\n`);\r\n\r\n const { exec } = await import(\"node:child_process\");\r\n const openCmd =\r\n process.platform === \"darwin\"\r\n ? \"open\"\r\n : process.platform === \"win32\"\r\n ? \"start\"\r\n : \"xdg-open\";\r\n exec(`${openCmd} \"${authorizeUrl}\"`);\r\n\r\n const tokenData = await startUserOAuthFlow(scope, profile);\r\n await saveUserToken(tokenData, profile);\r\n\r\n output(\r\n {\r\n success: true,\r\n message: \"User OAuth login successful\",\r\n scope: tokenData.scope,\r\n profile,\r\n },\r\n opts\r\n );\r\n}\r\n\r\nasync function handleServiceAccountLogin(\r\n opts: Record<string, unknown>\r\n): Promise<void> {\r\n let clientId = opts.clientId as string | undefined;\r\n let clientSecret = opts.clientSecret as string | undefined;\r\n let serviceAccount = opts.serviceAccount as string | undefined;\r\n let privateKeyPath = opts.privateKey as string | undefined;\r\n let botId = opts.botId as string | undefined;\r\n const domainId = opts.domainId as string | undefined;\r\n const profile = opts.profile as string;\r\n\r\n if (!clientId) clientId = process.env[\"NWORKS_CLIENT_ID\"];\r\n if (!clientSecret) clientSecret = process.env[\"NWORKS_CLIENT_SECRET\"];\r\n if (!serviceAccount) serviceAccount = process.env[\"NWORKS_SERVICE_ACCOUNT\"];\r\n if (!privateKeyPath) privateKeyPath = process.env[\"NWORKS_PRIVATE_KEY_PATH\"];\r\n if (!botId) botId = process.env[\"NWORKS_BOT_ID\"];\r\n\r\n if (process.stdin.isTTY) {\r\n if (!clientId) clientId = await prompt(\"Client ID: \");\r\n if (!clientSecret) clientSecret = await prompt(\"Client Secret: \");\r\n if (!serviceAccount)\r\n serviceAccount = await prompt(\"Service Account: \");\r\n if (!privateKeyPath)\r\n privateKeyPath = await prompt(\"Private Key Path: \");\r\n if (!botId) botId = await prompt(\"Bot ID: \");\r\n }\r\n\r\n if (!clientId || !clientSecret || !serviceAccount || !privateKeyPath || !botId) {\r\n throw new Error(\r\n \"Missing required fields. Use flags, environment variables, or run interactively.\"\r\n );\r\n }\r\n\r\n if (!existsSync(privateKeyPath)) {\r\n throw new Error(`Private key file not found: ${privateKeyPath}`);\r\n }\r\n\r\n await readFile(privateKeyPath, \"utf-8\");\r\n\r\n const creds: Credentials = {\r\n clientId,\r\n clientSecret,\r\n serviceAccount,\r\n privateKeyPath,\r\n botId,\r\n domainId,\r\n };\r\n\r\n await saveCredentials(creds, profile);\r\n\r\n await refreshToken(profile);\r\n\r\n output(\r\n { success: true, message: `Logged in as ${serviceAccount}`, profile },\r\n opts\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","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 } 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 { 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","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 { Command } from \"commander\";\r\nimport { clearCredentials } from \"../auth/config.js\";\r\nimport { output } from \"../output/format.js\";\r\nimport { cliError } from \"../output/cli-error.js\";\r\n\r\nexport const logoutCommand = new Command(\"logout\")\r\n .description(\"Remove stored credentials and tokens\")\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 profile = opts.profile as string;\r\n await clearCredentials(profile);\r\n output({ success: true, message: `Logged out (profile: ${profile})` }, opts);\r\n } catch (err) {\r\n cliError(err, opts);\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 { Command } from \"commander\";\r\nimport { loadCredentials, loadToken } from \"../auth/config.js\";\r\nimport { output } from \"../output/format.js\";\r\nimport { cliError } from \"../output/cli-error.js\";\r\n\r\nexport const whoamiCommand = new Command(\"whoami\")\r\n .description(\"Show current authentication status\")\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 profile = opts.profile as string;\r\n const creds = await loadCredentials(profile);\r\n const token = await loadToken(profile);\r\n\r\n const expiresAt = token ? token.expiresAt : null;\r\n const isValid =\r\n typeof expiresAt === \"number\" && !isNaN(expiresAt)\r\n ? expiresAt > Date.now() / 1000\r\n : false;\r\n\r\n let tokenExpiresAt = \"(no token)\";\r\n if (typeof expiresAt === \"number\" && !isNaN(expiresAt) && expiresAt > 0) {\r\n tokenExpiresAt = new Date(expiresAt * 1000).toISOString();\r\n }\r\n\r\n output(\r\n {\r\n profile,\r\n serviceAccount: creds.serviceAccount ?? \"(not set)\",\r\n clientId: creds.clientId,\r\n botId: creds.botId ?? \"(not set)\",\r\n domainId: creds.domainId ?? \"(not set)\",\r\n tokenValid: isValid,\r\n tokenExpiresAt,\r\n },\r\n opts\r\n );\r\n } catch (err) {\r\n cliError(err, opts);\r\n }\r\n });\r\n","import { Command } from \"commander\";\r\nimport * as messageApi from \"../api/message.js\";\r\nimport { output } from \"../output/format.js\";\r\nimport { cliError } from \"../output/cli-error.js\";\r\n\r\nconst sendCommand = new Command(\"send\")\r\n .description(\"Send a message to a user or channel\")\r\n .option(\"--to <userId>\", \"Recipient user ID\")\r\n .option(\"--channel <channelId>\", \"Channel ID\")\r\n .requiredOption(\"--text <text>\", \"Message text\")\r\n .option(\"--type <type>\", \"Message type: text, button, list\", \"text\")\r\n .option(\"--actions <json>\", \"Button actions JSON (type=button)\")\r\n .option(\"--elements <json>\", \"List elements JSON (type=list)\")\r\n .option(\"--profile <name>\", \"Profile name\", \"default\")\r\n .option(\"--json\", \"JSON output\")\r\n .option(\"--dry-run\", \"Print request without sending\")\r\n .action(async (opts) => {\r\n try {\r\n if (!opts.to && !opts.channel) {\r\n throw new Error(\"Either --to or --channel is required.\");\r\n }\r\n\r\n const sendOpts: messageApi.SendOptions = {\r\n to: opts.to as string | undefined,\r\n channel: opts.channel as string | undefined,\r\n text: opts.text as string,\r\n type: opts.type as messageApi.MessageType,\r\n actions: opts.actions as string | undefined,\r\n elements: opts.elements as string | undefined,\r\n profile: opts.profile as string,\r\n };\r\n\r\n if (opts.dryRun) {\r\n output({ dryRun: true, request: sendOpts }, opts);\r\n return;\r\n }\r\n\r\n const result = await messageApi.send(sendOpts);\r\n output(result, opts);\r\n } catch (err) {\r\n cliError(err, opts);\r\n }\r\n });\r\n\r\nconst membersCommand = new Command(\"members\")\r\n .description(\"List members of a channel\")\r\n .requiredOption(\"--channel <channelId>\", \"Channel ID\")\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 result = await messageApi.listMembers(\r\n opts.channel as string,\r\n opts.profile as string\r\n );\r\n output(result, opts);\r\n } catch (err) {\r\n cliError(err, opts);\r\n }\r\n });\r\n\r\nexport const messageCommand = new Command(\"message\")\r\n .description(\"Bot message operations\")\r\n .addCommand(sendCommand)\r\n .addCommand(membersCommand);\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 { Command } from \"commander\";\r\nimport * as directoryApi from \"../api/directory.js\";\r\nimport { output } from \"../output/format.js\";\r\nimport { cliError } from \"../output/cli-error.js\";\r\n\r\nconst membersCommand = new Command(\"members\")\r\n .description(\"List organization members (requires directory.read scope)\")\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 result = await directoryApi.listUsers(opts.profile as string);\r\n const formatted = {\r\n users: result.users.map((u) => ({\r\n userId: u.userId,\r\n userName: [u.userName?.lastName, u.userName?.firstName]\r\n .filter(Boolean)\r\n .join(\" \") || \"\",\r\n email: u.email ?? \"\",\r\n cellPhone: (u as unknown as Record<string, unknown>).cellPhone as string ?? \"\",\r\n organization:\r\n u.organizations\r\n ?.find((o) => o.primary)?.organizationName ??\r\n u.organizations?.[0]?.organizationName ??\r\n \"\",\r\n })),\r\n };\r\n output(formatted, opts);\r\n } catch (err) {\r\n cliError(err, opts);\r\n }\r\n });\r\n\r\nexport const directoryCommand = new Command(\"directory\")\r\n .description(\"Directory (organization) operations\")\r\n .addCommand(membersCommand);\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 { Command } from \"commander\";\nimport * as calendarApi from \"../api/calendar.js\";\nimport { output } from \"../output/format.js\";\nimport { cliError } from \"../output/cli-error.js\";\n\nfunction todayRange(): { from: string; until: string } {\n const now = new Date();\n const yyyy = now.getFullYear();\n const mm = String(now.getMonth() + 1).padStart(2, \"0\");\n const dd = String(now.getDate()).padStart(2, \"0\");\n return {\n from: `${yyyy}-${mm}-${dd}T00:00:00+09:00`,\n until: `${yyyy}-${mm}-${dd}T23:59:59+09:00`,\n };\n}\n\nconst listCommand = new Command(\"list\")\n .description(\"List calendar events (requires User OAuth with calendar.read or calendar scope)\")\n .option(\"--user <userId>\", \"Target user ID (default: me)\")\n .option(\"--from <dateTime>\", \"Start (YYYY-MM-DDThh:mm:ss+09:00, default: today 00:00)\")\n .option(\"--until <dateTime>\", \"End (YYYY-MM-DDThh:mm:ss+09:00, default: today 23:59)\")\n .option(\"--profile <name>\", \"Profile name\", \"default\")\n .option(\"--json\", \"JSON output\")\n .action(async (opts) => {\n try {\n const defaults = todayRange();\n const from = (opts.from as string | undefined) ?? defaults.from;\n const until = (opts.until as string | undefined) ?? defaults.until;\n const userId = (opts.user as string | undefined) ?? \"me\";\n\n const result = await calendarApi.listEvents(\n from,\n until,\n userId,\n opts.profile as string\n );\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\n ? `${c.start.dateTime} (${c.start.timeZone ?? \"\"})`\n : c.start.date ?? \"\",\n end: c.end.dateTime\n ? `${c.end.dateTime} (${c.end.timeZone ?? \"\"})`\n : c.end.date ?? \"\",\n location: c.location ?? \"\",\n }))\n );\n\n output({ events, count: events.length }, opts);\n } catch (err) {\n cliError(err, opts, \"calendar\");\n }\n });\n\nconst createCommand = new Command(\"create\")\n .description(\"Create a calendar event (requires User OAuth with calendar scope)\")\n .requiredOption(\"--title <title>\", \"Event title (summary)\")\n .requiredOption(\"--start <dateTime>\", \"Start (YYYY-MM-DDThh:mm:ss)\")\n .requiredOption(\"--end <dateTime>\", \"End (YYYY-MM-DDThh:mm:ss)\")\n .option(\"--tz <timeZone>\", \"Time zone (default: Asia/Seoul)\", \"Asia/Seoul\")\n .option(\"--description <text>\", \"Event description\")\n .option(\"--location <place>\", \"Event location\")\n .option(\"--attendees <emails>\", \"Attendee emails (comma-separated)\")\n .option(\"--notify\", \"Send notification to attendees\")\n .option(\"--user <userId>\", \"Target user ID (default: me)\")\n .option(\"--profile <name>\", \"Profile name\", \"default\")\n .option(\"--json\", \"JSON output\")\n .action(async (opts) => {\n try {\n const attendees = opts.attendees\n ? (opts.attendees as string).split(\",\").map((e: string) => ({ email: e.trim() }))\n : undefined;\n\n const result = await calendarApi.createEvent({\n summary: opts.title as string,\n start: opts.start as string,\n end: opts.end as string,\n timeZone: opts.tz as string,\n description: opts.description as string | undefined,\n location: opts.location as string | undefined,\n attendees,\n sendNotification: (opts.notify as boolean | undefined) ?? false,\n userId: (opts.user as string | undefined) ?? \"me\",\n profile: opts.profile as string,\n });\n\n const event = result.eventComponents?.[0];\n const fmt = (t?: { dateTime?: string; timeZone?: string }) =>\n t?.dateTime ? `${t.dateTime} (${t.timeZone ?? \"\"})` : \"\";\n output(\n {\n success: true,\n eventId: event?.eventId,\n summary: event?.summary,\n start: fmt(event?.start),\n end: fmt(event?.end),\n },\n opts\n );\n } catch (err) {\n cliError(err, opts, \"calendar\");\n }\n });\n\nconst updateCommand = new Command(\"update\")\n .description(\"Update a calendar event (requires User OAuth with calendar scope)\")\n .requiredOption(\"--id <eventId>\", \"Event ID\")\n .option(\"--title <title>\", \"New title (summary)\")\n .option(\"--start <dateTime>\", \"New start (YYYY-MM-DDThh:mm:ss)\")\n .option(\"--end <dateTime>\", \"New end (YYYY-MM-DDThh:mm:ss)\")\n .option(\"--tz <timeZone>\", \"Time zone (default: Asia/Seoul)\", \"Asia/Seoul\")\n .option(\"--description <text>\", \"New description\")\n .option(\"--location <place>\", \"New location\")\n .option(\"--attendees <emails>\", \"Attendee emails (comma-separated)\")\n .option(\"--notify\", \"Send notification to attendees\")\n .option(\"--user <userId>\", \"Target user ID (default: me)\")\n .option(\"--profile <name>\", \"Profile name\", \"default\")\n .option(\"--json\", \"JSON output\")\n .action(async (opts) => {\n try {\n const hasUpdate =\n opts.title || opts.start || opts.end || opts.description || opts.location || opts.attendees;\n if (!hasUpdate) {\n throw new Error(\"Specify at least one of: --title, --start, --end, --description, --location, --attendees\");\n }\n\n const attendees = opts.attendees\n ? (opts.attendees as string).split(\",\").map((e: string) => ({ email: e.trim() }))\n : undefined;\n\n await calendarApi.updateEvent({\n eventId: opts.id as string,\n summary: opts.title as string | undefined,\n start: opts.start as string | undefined,\n end: opts.end as string | undefined,\n timeZone: opts.tz as string,\n description: opts.description as string | undefined,\n location: opts.location as string | undefined,\n attendees,\n sendNotification: (opts.notify as boolean | undefined) ?? false,\n userId: (opts.user as string | undefined) ?? \"me\",\n profile: opts.profile as string,\n });\n\n output(\n { success: true, eventId: opts.id, message: \"Event updated\" },\n opts\n );\n } catch (err) {\n cliError(err, opts, \"calendar\");\n }\n });\n\nconst deleteCommand = new Command(\"delete\")\n .description(\"Delete a calendar event (requires User OAuth with calendar scope)\")\n .requiredOption(\"--id <eventId>\", \"Event ID\")\n .option(\"--notify\", \"Send notification to attendees\")\n .option(\"--user <userId>\", \"Target user ID (default: me)\")\n .option(\"--profile <name>\", \"Profile name\", \"default\")\n .option(\"--json\", \"JSON output\")\n .action(async (opts) => {\n try {\n await calendarApi.deleteEvent(\n opts.id as string,\n (opts.user as string | undefined) ?? \"me\",\n (opts.notify as boolean | undefined) ?? false,\n opts.profile as string\n );\n output({ success: true, eventId: opts.id, message: \"Event deleted\" }, opts);\n } catch (err) {\n cliError(err, opts, \"calendar\");\n }\n });\n\nexport const calendarCommand = new Command(\"calendar\")\n .description(\"Calendar operations (requires User OAuth)\")\n .addCommand(listCommand)\n .addCommand(createCommand)\n .addCommand(updateCommand)\n .addCommand(deleteCommand);\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 { 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 { writeFile } from \"node:fs/promises\";\r\nimport { join } from \"node:path\";\r\nimport { Command } from \"commander\";\r\nimport * as driveApi from \"../api/drive.js\";\r\nimport { output } from \"../output/format.js\";\r\nimport { cliError } from \"../output/cli-error.js\";\r\n\r\nconst listCommand = new Command(\"list\")\r\n .description(\"List files in Drive (requires User OAuth with file or file.read scope)\")\r\n .option(\"--user <userId>\", \"Target user ID (default: me)\")\r\n .option(\"--folder <folderId>\", \"Folder ID to list (default: root)\")\r\n .option(\"--count <n>\", \"Items per page (default: 20)\", \"20\")\r\n .option(\"--cursor <cursor>\", \"Pagination cursor\")\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 result = await driveApi.listFiles(\r\n (opts.user as string | undefined) ?? \"me\",\r\n opts.folder as string | undefined,\r\n parseInt(opts.count as string, 10),\r\n opts.cursor as string | undefined,\r\n opts.profile as string\r\n );\r\n\r\n const files = result.files.map((f) => ({\r\n name: f.fileName,\r\n type: f.fileType,\r\n size: f.fileSize,\r\n modified: f.modifiedTime,\r\n fileId: f.fileId,\r\n }));\r\n\r\n output(\r\n {\r\n files,\r\n count: files.length,\r\n nextCursor: result.responseMetaData?.nextCursor ?? null,\r\n },\r\n opts\r\n );\r\n } catch (err) {\r\n cliError(err, opts, \"drive\");\r\n }\r\n });\r\n\r\nconst uploadCommand = new Command(\"upload\")\r\n .description(\"Upload a file to Drive (requires User OAuth with file scope)\")\r\n .requiredOption(\"--file <path>\", \"Local file path to upload\")\r\n .option(\"--user <userId>\", \"Target user ID (default: me)\")\r\n .option(\"--folder <folderId>\", \"Destination folder ID (default: root)\")\r\n .option(\"--overwrite\", \"Overwrite if file exists\", false)\r\n .option(\"--profile <name>\", \"Profile name\", \"default\")\r\n .option(\"--json\", \"JSON output\")\r\n .option(\"--dry-run\", \"Print request without uploading\")\r\n .action(async (opts) => {\r\n try {\r\n if (opts.dryRun) {\r\n output(\r\n {\r\n dryRun: true,\r\n request: {\r\n file: opts.file,\r\n user: opts.user ?? \"me\",\r\n folder: opts.folder ?? \"(root)\",\r\n overwrite: opts.overwrite,\r\n },\r\n },\r\n opts\r\n );\r\n return;\r\n }\r\n\r\n const result = await driveApi.uploadFile(\r\n opts.file as string,\r\n (opts.user as string | undefined) ?? \"me\",\r\n opts.folder as string | undefined,\r\n opts.overwrite as boolean,\r\n opts.profile as string\r\n );\r\n\r\n output(\r\n {\r\n success: true,\r\n fileId: result.fileId,\r\n fileName: result.fileName,\r\n fileSize: result.fileSize,\r\n filePath: result.filePath,\r\n fileType: result.fileType,\r\n },\r\n opts\r\n );\r\n } catch (err) {\r\n cliError(err, opts, \"drive\");\r\n }\r\n });\r\n\r\nconst downloadCommand = new Command(\"download\")\r\n .description(\"Download a file from Drive (requires User OAuth with file or file.read scope)\")\r\n .requiredOption(\"--file-id <fileId>\", \"File ID to download\")\r\n .option(\"--out <path>\", \"Output directory (default: current directory)\")\r\n .option(\"--name <filename>\", \"Output filename (default: original name)\")\r\n .option(\"--user <userId>\", \"Target user ID (default: me)\")\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 result = await driveApi.downloadFile(\r\n opts.fileId as string,\r\n (opts.user as string | undefined) ?? \"me\",\r\n opts.profile as string\r\n );\r\n\r\n const fileName =\r\n (opts.name as string | undefined) ?? result.fileName ?? opts.fileId as string;\r\n const outDir = (opts.out as string | undefined) ?? process.cwd();\r\n const outPath = join(outDir, fileName);\r\n\r\n await writeFile(outPath, result.buffer);\r\n\r\n output(\r\n {\r\n success: true,\r\n fileName,\r\n path: outPath,\r\n size: result.buffer.length,\r\n },\r\n opts\r\n );\r\n } catch (err) {\r\n cliError(err, opts, \"drive\");\r\n }\r\n });\r\n\r\nexport const driveCommand = new Command(\"drive\")\r\n .description(\"Drive operations (requires User OAuth with file scope)\")\r\n .addCommand(listCommand)\r\n .addCommand(uploadCommand)\r\n .addCommand(downloadCommand);\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 { Command } from \"commander\";\r\nimport * as mailApi from \"../api/mail.js\";\r\nimport { output } from \"../output/format.js\";\r\nimport { cliError } from \"../output/cli-error.js\";\r\n\r\nconst sendCommand = new Command(\"send\")\r\n .description(\"Send a mail (requires User OAuth with mail scope)\")\r\n .requiredOption(\"--to <emails>\", \"Recipient email addresses (separate with ;)\")\r\n .requiredOption(\"--subject <subject>\", \"Mail subject\")\r\n .option(\"--body <body>\", \"Mail body content\")\r\n .option(\"--cc <emails>\", \"CC email addresses (separate with ;)\")\r\n .option(\"--bcc <emails>\", \"BCC email addresses (separate with ;)\")\r\n .option(\"--content-type <type>\", \"Body format: html or text\", \"html\")\r\n .option(\"--user <userId>\", \"Sender user ID (default: me)\")\r\n .option(\"--profile <name>\", \"Profile name\", \"default\")\r\n .option(\"--json\", \"JSON output\")\r\n .option(\"--dry-run\", \"Print request without sending\")\r\n .action(async (opts) => {\r\n try {\r\n const sendOpts: mailApi.SendMailOptions = {\r\n to: opts.to as string,\r\n subject: opts.subject as string,\r\n body: opts.body as string | undefined,\r\n cc: opts.cc as string | undefined,\r\n bcc: opts.bcc as string | undefined,\r\n contentType: opts.contentType as \"html\" | \"text\",\r\n userId: (opts.user as string | undefined) ?? \"me\",\r\n profile: opts.profile as string,\r\n };\r\n\r\n if (opts.dryRun) {\r\n output({ dryRun: true, request: sendOpts }, opts);\r\n return;\r\n }\r\n\r\n await mailApi.sendMail(sendOpts);\r\n output({ success: true, message: \"Mail sent (async)\" }, opts);\r\n } catch (err) {\r\n cliError(err, opts, \"mail\");\r\n }\r\n });\r\n\r\nconst listCommand = new Command(\"list\")\r\n .description(\"List mails in a folder (requires User OAuth with mail or mail.read scope)\")\r\n .option(\"--folder <folderId>\", \"Folder ID (default: 0 = inbox)\", \"0\")\r\n .option(\"--count <n>\", \"Items per page (default: 30)\", \"30\")\r\n .option(\"--cursor <cursor>\", \"Pagination cursor\")\r\n .option(\"--unread\", \"Show unread mails only\", false)\r\n .option(\"--user <userId>\", \"Target user ID (default: me)\")\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 result = await mailApi.listMails(\r\n parseInt(opts.folder as string, 10),\r\n (opts.user as string | undefined) ?? \"me\",\r\n parseInt(opts.count as string, 10),\r\n opts.cursor as string | undefined,\r\n opts.unread as boolean,\r\n opts.profile as string\r\n );\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\r\n output(\r\n {\r\n mails,\r\n count: mails.length,\r\n totalCount: result.totalCount,\r\n unreadCount: result.unreadCount,\r\n folderName: result.folderName,\r\n nextCursor: result.responseMetaData?.nextCursor ?? null,\r\n },\r\n opts\r\n );\r\n } catch (err) {\r\n cliError(err, opts, \"mail\");\r\n }\r\n });\r\n\r\nconst readCommand = new Command(\"read\")\r\n .description(\"Read a specific mail (requires User OAuth with mail or mail.read scope)\")\r\n .requiredOption(\"--id <mailId>\", \"Mail ID\")\r\n .option(\"--user <userId>\", \"Target user ID (default: me)\")\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 result = await mailApi.readMail(\r\n parseInt(opts.id as string, 10),\r\n (opts.user as string | undefined) ?? \"me\",\r\n opts.profile as string\r\n );\r\n\r\n const mail = result.mail;\r\n output(\r\n {\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 opts\r\n );\r\n } catch (err) {\r\n cliError(err, opts, \"mail\");\r\n }\r\n });\r\n\r\nexport const mailCommand = new Command(\"mail\")\r\n .description(\"Mail operations (requires User OAuth with mail scope)\")\r\n .addCommand(sendCommand)\r\n .addCommand(listCommand)\r\n .addCommand(readCommand);\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 { Command } from \"commander\";\r\nimport * as taskApi from \"../api/task.js\";\r\nimport { output } from \"../output/format.js\";\r\nimport { cliError } from \"../output/cli-error.js\";\r\n\r\nconst listCommand = new Command(\"list\")\r\n .description(\"List tasks (requires User OAuth with task or task.read scope)\")\r\n .option(\"--category <categoryId>\", \"Category ID (default: default)\", \"default\")\r\n .option(\"--status <status>\", \"Filter: TODO or ALL (default: ALL)\", \"ALL\")\r\n .option(\"--count <n>\", \"Items per page (default: 50)\", \"50\")\r\n .option(\"--cursor <cursor>\", \"Pagination cursor\")\r\n .option(\"--user <userId>\", \"Target user ID (default: me)\")\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 result = await taskApi.listTasks(\r\n opts.category as string,\r\n (opts.user as string | undefined) ?? \"me\",\r\n parseInt(opts.count as string, 10),\r\n opts.cursor as string | undefined,\r\n opts.status as \"TODO\" | \"ALL\",\r\n opts.profile as string\r\n );\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\r\n output(\r\n {\r\n tasks,\r\n count: tasks.length,\r\n nextCursor: result.responseMetaData?.nextCursor ?? null,\r\n },\r\n opts\r\n );\r\n } catch (err) {\r\n cliError(err, opts, \"task\");\r\n }\r\n });\r\n\r\nconst createCommand = new Command(\"create\")\r\n .description(\"Create a task (requires User OAuth with task scope)\")\r\n .requiredOption(\"--title <title>\", \"Task title\")\r\n .option(\"--body <content>\", \"Task content/description\")\r\n .option(\"--due <date>\", \"Due date (YYYY-MM-DD)\")\r\n .option(\"--category <categoryId>\", \"Category ID\")\r\n .option(\"--assignee <userIds>\", \"Assignee user IDs (comma-separated)\")\r\n .option(\"--user <userId>\", \"Creator user ID (default: me)\")\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 assigneeIds = opts.assignee\r\n ? (opts.assignee as string).split(\",\").map((s: string) => s.trim())\r\n : undefined;\r\n\r\n const result = await taskApi.createTask({\r\n title: opts.title as string,\r\n content: opts.body as string | undefined,\r\n dueDate: opts.due as string | undefined,\r\n categoryId: opts.category as string | undefined,\r\n assigneeIds,\r\n userId: (opts.user as string | undefined) ?? \"me\",\r\n profile: opts.profile as string,\r\n });\r\n\r\n output(\r\n {\r\n success: true,\r\n taskId: result.taskId,\r\n title: result.title,\r\n status: result.status,\r\n dueDate: result.dueDate,\r\n },\r\n opts\r\n );\r\n } catch (err) {\r\n cliError(err, opts, \"task\");\r\n }\r\n });\r\n\r\nconst updateCommand = new Command(\"update\")\r\n .description(\"Update a task (requires User OAuth with task scope)\")\r\n .requiredOption(\"--id <taskId>\", \"Task ID\")\r\n .option(\"--title <title>\", \"New title\")\r\n .option(\"--body <content>\", \"New content\")\r\n .option(\"--due <date>\", \"New due date (YYYY-MM-DD)\")\r\n .option(\"--status <status>\", \"Set status: done or todo\")\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 profile = opts.profile as string;\r\n const taskId = opts.id as string;\r\n const status = opts.status as string | undefined;\r\n\r\n if (status) {\r\n if (status.toLowerCase() === \"done\") {\r\n await taskApi.completeTask(taskId, profile);\r\n } else if (status.toLowerCase() === \"todo\") {\r\n await taskApi.incompleteTask(taskId, profile);\r\n } else {\r\n throw new Error(\"Invalid status. Use 'done' or 'todo'.\");\r\n }\r\n }\r\n\r\n const hasFieldUpdate = opts.title || opts.body || opts.due;\r\n if (hasFieldUpdate) {\r\n const result = await taskApi.updateTask({\r\n taskId,\r\n title: opts.title as string | undefined,\r\n content: opts.body as string | undefined,\r\n dueDate: opts.due as string | undefined,\r\n profile,\r\n });\r\n output(\r\n {\r\n success: true,\r\n taskId: result.taskId,\r\n title: result.title,\r\n status: result.status,\r\n dueDate: result.dueDate,\r\n },\r\n opts\r\n );\r\n } else if (status) {\r\n output(\r\n { success: true, taskId, status: status.toLowerCase() === \"done\" ? \"DONE\" : \"TODO\" },\r\n opts\r\n );\r\n } else {\r\n throw new Error(\"Specify at least one of: --title, --body, --due, --status\");\r\n }\r\n } catch (err) {\r\n cliError(err, opts, \"task\");\r\n }\r\n });\r\n\r\nconst deleteCommand = new Command(\"delete\")\r\n .description(\"Delete a task (requires User OAuth with task scope)\")\r\n .requiredOption(\"--id <taskId>\", \"Task ID\")\r\n .option(\"--profile <name>\", \"Profile name\", \"default\")\r\n .option(\"--json\", \"JSON output\")\r\n .action(async (opts) => {\r\n try {\r\n await taskApi.deleteTask(\r\n opts.id as string,\r\n opts.profile as string\r\n );\r\n output({ success: true, taskId: opts.id, message: \"Task deleted\" }, opts);\r\n } catch (err) {\r\n cliError(err, opts, \"task\");\r\n }\r\n });\r\n\r\nexport const taskCommand = new Command(\"task\")\r\n .description(\"Task operations (requires User OAuth with task scope)\")\r\n .addCommand(listCommand)\r\n .addCommand(createCommand)\r\n .addCommand(updateCommand)\r\n .addCommand(deleteCommand);\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 { Command } from \"commander\";\r\nimport * as boardApi from \"../api/board.js\";\r\nimport { output } from \"../output/format.js\";\r\nimport { cliError } from \"../output/cli-error.js\";\r\n\r\nconst listCommand = new Command(\"list\")\r\n .description(\"List boards (requires User OAuth with board or board.read scope)\")\r\n .option(\"--count <n>\", \"Items per page (default: 20)\", \"20\")\r\n .option(\"--cursor <cursor>\", \"Pagination cursor\")\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 result = await boardApi.listBoards(\r\n parseInt(opts.count as string, 10),\r\n opts.cursor as string | undefined,\r\n opts.profile as string\r\n );\r\n\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\r\n output(\r\n { boards, count: boards.length, nextCursor: result.responseMetaData?.nextCursor ?? null },\r\n opts\r\n );\r\n } catch (err) {\r\n cliError(err, opts, \"board\");\r\n }\r\n });\r\n\r\nconst postsCommand = new Command(\"posts\")\r\n .description(\"List posts in a board (requires User OAuth with board or board.read scope)\")\r\n .requiredOption(\"--board <boardId>\", \"Board ID\")\r\n .option(\"--count <n>\", \"Items per page (default: 20)\", \"20\")\r\n .option(\"--cursor <cursor>\", \"Pagination cursor\")\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 result = await boardApi.listPosts(\r\n opts.board as string,\r\n parseInt(opts.count as string, 10),\r\n opts.cursor as string | undefined,\r\n opts.profile as string\r\n );\r\n\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\r\n output(\r\n { posts, count: posts.length, nextCursor: result.responseMetaData?.nextCursor ?? null },\r\n opts\r\n );\r\n } catch (err) {\r\n cliError(err, opts, \"board\");\r\n }\r\n });\r\n\r\nconst readCommand = new Command(\"read\")\r\n .description(\"Read a post detail (requires User OAuth with board or board.read scope)\")\r\n .requiredOption(\"--board <boardId>\", \"Board ID\")\r\n .requiredOption(\"--post <postId>\", \"Post ID\")\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 post = await boardApi.readPost(\r\n opts.board as string,\r\n opts.post as string,\r\n opts.profile as string\r\n );\r\n\r\n output(\r\n {\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 opts\r\n );\r\n } catch (err) {\r\n cliError(err, opts, \"board\");\r\n }\r\n });\r\n\r\nconst createCommand = new Command(\"create\")\r\n .description(\"Create a post in a board (requires User OAuth with board scope)\")\r\n .requiredOption(\"--board <boardId>\", \"Board ID\")\r\n .requiredOption(\"--title <title>\", \"Post title\")\r\n .option(\"--body <text>\", \"Post body\")\r\n .option(\"--no-comment\", \"Disable comments\")\r\n .option(\"--notify\", \"Send notification\")\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 post = await boardApi.createPost({\r\n boardId: opts.board as string,\r\n title: opts.title as string,\r\n body: opts.body as string | undefined,\r\n enableComment: opts.comment as boolean,\r\n sendNotifications: (opts.notify as boolean | undefined) ?? false,\r\n profile: opts.profile as string,\r\n });\r\n\r\n output(\r\n {\r\n success: true,\r\n postId: post.postId,\r\n boardId: post.boardId,\r\n title: post.title,\r\n },\r\n opts\r\n );\r\n } catch (err) {\r\n cliError(err, opts, \"board\");\r\n }\r\n });\r\n\r\nexport const boardCommand = new Command(\"board\")\r\n .description(\"Board operations (requires User OAuth)\")\r\n .addCommand(listCommand)\r\n .addCommand(postsCommand)\r\n .addCommand(readCommand)\r\n .addCommand(createCommand);\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 { startMcpServer } from \"../mcp/server.js\";\r\n\r\nexport const mcpCommand = new Command(\"mcp\")\r\n .description(\"Start MCP server (stdio transport)\")\r\n .option(\"--list-tools\", \"List available MCP tools\")\r\n .action(async (opts) => {\r\n if (opts.listTools) {\r\n console.log(\"nworks_message_send — Send message to user or channel\");\r\n console.log(\"nworks_message_members — List channel members\");\r\n console.log(\"nworks_directory_members — List organization members\");\r\n console.log(\"nworks_calendar_list — List calendar events (User OAuth)\");\r\n console.log(\"nworks_whoami — Show auth status\");\r\n return;\r\n }\r\n\r\n await startMcpServer();\r\n });\r\n","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","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"],"mappings":"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","names":["Command","readFile","existsSync","readFile","readFile","AUTH_URL","refreshToken","existsSync","readFile","Command","Command","Command","Command","Command","Command","Command","membersCommand","Command","Command","BASE_URL","Command","writeFile","join","Command","readFile","BASE_URL","authedFetch","handleError","readFile","listCommand","Command","join","writeFile","Command","BASE_URL","authedFetch","handleError","sendCommand","Command","listCommand","Command","BASE_URL","authedFetch","handleError","BASE_URL","authedFetch","handleError","BASE_URL","authedFetch","handleError","listCommand","Command","createCommand","updateCommand","deleteCommand","Command","BASE_URL","authedFetch","handleError","listCommand","Command","readCommand","createCommand","Command","Command","existsSync","readFile","existsSync","readFile","Command","writeFile","join","Command","require","Command"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/login.ts","../src/auth/config.ts","../src/utils/error.ts","../src/auth/jwt.ts","../src/auth/token.ts","../src/auth/oauth-user.ts","../src/output/format.ts","../src/commands/logout.ts","../src/utils/error-hints.ts","../src/output/cli-error.ts","../src/commands/whoami.ts","../src/commands/message.ts","../src/api/client.ts","../src/api/message.ts","../src/commands/directory.ts","../src/api/directory.ts","../src/commands/calendar.ts","../src/api/calendar.ts","../src/auth/token-user.ts","../src/commands/drive.ts","../src/api/drive.ts","../src/commands/mail.ts","../src/api/mail.ts","../src/commands/task.ts","../src/api/task.ts","../src/commands/board.ts","../src/api/board.ts","../src/commands/mcp-cmd.ts","../src/mcp/server.ts","../src/mcp/tools.ts","../src/commands/doctor.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\r\nimport { Command } from \"commander\";\r\nimport { loginCommand } from \"./commands/login.js\";\r\nimport { logoutCommand } from \"./commands/logout.js\";\r\nimport { whoamiCommand } from \"./commands/whoami.js\";\r\nimport { messageCommand } from \"./commands/message.js\";\r\nimport { directoryCommand } from \"./commands/directory.js\";\r\nimport { calendarCommand } from \"./commands/calendar.js\";\r\nimport { driveCommand } from \"./commands/drive.js\";\r\nimport { mailCommand } from \"./commands/mail.js\";\r\nimport { taskCommand } from \"./commands/task.js\";\r\nimport { boardCommand } from \"./commands/board.js\";\r\nimport { mcpCommand } from \"./commands/mcp-cmd.js\";\r\nimport { doctorCommand } from \"./commands/doctor.js\";\r\n\r\nconst require = createRequire(import.meta.url);\r\nconst { version } = require(\"../package.json\") as { version: string };\r\n\r\nconst program = new Command()\r\n .name(\"nworks\")\r\n .description(\"NAVER WORKS CLI — built for humans and AI agents\")\r\n .version(version)\r\n .option(\"--json\", \"Always output JSON\")\r\n .option(\"-v, --verbose\", \"Debug logging\")\r\n .option(\"--dry-run\", \"Print request without calling API\")\r\n .option(\"-p, --profile <name>\", \"Profile name\", \"default\");\r\n\r\nprogram.addCommand(loginCommand);\r\nprogram.addCommand(logoutCommand);\r\nprogram.addCommand(whoamiCommand);\r\nprogram.addCommand(messageCommand);\r\nprogram.addCommand(directoryCommand);\r\nprogram.addCommand(calendarCommand);\r\nprogram.addCommand(driveCommand);\r\nprogram.addCommand(mailCommand);\r\nprogram.addCommand(taskCommand);\r\nprogram.addCommand(boardCommand);\r\nprogram.addCommand(mcpCommand);\r\nprogram.addCommand(doctorCommand);\r\n\r\nprogram.parse();\r\n","import { Command } from \"commander\";\r\nimport { readFile } from \"node:fs/promises\";\r\nimport { existsSync } from \"node:fs\";\r\nimport { createInterface } from \"node:readline/promises\";\r\nimport { saveCredentials, saveUserToken, loadCredentials, type Credentials } from \"../auth/config.js\";\r\nimport { refreshToken } from \"../auth/token.js\";\r\nimport { startUserOAuthFlow, buildAuthorizeUrl } from \"../auth/oauth-user.js\";\r\nimport { output, errorOutput } from \"../output/format.js\";\r\nimport { randomBytes } from \"node:crypto\";\r\n\r\nasync function prompt(question: string): Promise<string> {\r\n const rl = createInterface({\r\n input: process.stdin,\r\n output: process.stdout,\r\n });\r\n try {\r\n const answer = await rl.question(question);\r\n return answer.trim();\r\n } finally {\r\n rl.close();\r\n }\r\n}\r\n\r\nexport const loginCommand = new Command(\"login\")\r\n .description(\"Authenticate with NAVER WORKS\")\r\n .option(\"--user\", \"User OAuth login (opens browser)\")\r\n .option(\"--scope <scope>\", \"OAuth scope for user login\", \"calendar.read\")\r\n .option(\"--client-id <id>\", \"Client ID\")\r\n .option(\"--client-secret <secret>\", \"Client Secret\")\r\n .option(\"--service-account <account>\", \"Service Account ID\")\r\n .option(\"--private-key <path>\", \"Path to private key file (.key)\")\r\n .option(\"--bot-id <id>\", \"Bot ID\")\r\n .option(\"--domain-id <id>\", \"Domain ID (optional)\")\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 profile = opts.profile as string;\r\n\r\n if (opts.user) {\r\n await handleUserLogin(opts.scope as string, profile, opts);\r\n } else {\r\n await handleServiceAccountLogin(opts);\r\n }\r\n } catch (err) {\r\n const error = err as Error;\r\n errorOutput({ message: error.message }, opts);\r\n process.exitCode = 1;\r\n }\r\n });\r\n\r\nasync function handleUserLogin(\r\n scope: string,\r\n profile: string,\r\n opts: Record<string, unknown>\r\n): Promise<void> {\r\n let clientId = opts.clientId as string | undefined;\r\n let clientSecret = opts.clientSecret as string | undefined;\r\n\r\n try {\r\n const existing = await loadCredentials(profile);\r\n if (!clientId) clientId = existing.clientId;\r\n if (!clientSecret) clientSecret = existing.clientSecret;\r\n } catch {\r\n // ignore\r\n }\r\n\r\n if (process.stdin.isTTY) {\r\n if (!clientId) clientId = await prompt(\"Client ID: \");\r\n if (!clientSecret) clientSecret = await prompt(\"Client Secret: \");\r\n }\r\n\r\n if (!clientId || !clientSecret) {\r\n throw new Error(\r\n \"Client ID and Client Secret are required for User OAuth.\\n\" +\r\n \"Use --client-id and --client-secret flags, or set NWORKS_CLIENT_ID / NWORKS_CLIENT_SECRET env vars.\"\r\n );\r\n }\r\n\r\n try {\r\n const existing = await loadCredentials(profile);\r\n await saveCredentials({ ...existing, clientId, clientSecret }, profile);\r\n } catch {\r\n await saveCredentials({ clientId, clientSecret }, profile);\r\n }\r\n\r\n const state = randomBytes(16).toString(\"hex\");\r\n const authorizeUrl = buildAuthorizeUrl(clientId, scope, state);\r\n\r\n console.error(`\\nOpening browser for NAVER WORKS login...`);\r\n console.error(`If the browser does not open, visit this URL:\\n`);\r\n console.error(` ${authorizeUrl}\\n`);\r\n\r\n const { exec } = await import(\"node:child_process\");\r\n const openCmd =\r\n process.platform === \"darwin\"\r\n ? \"open\"\r\n : process.platform === \"win32\"\r\n ? \"start\"\r\n : \"xdg-open\";\r\n if (process.platform === \"win32\") {\r\n exec(`start \"\" \"${authorizeUrl}\"`);\r\n } else {\r\n exec(`${openCmd} \"${authorizeUrl}\"`);\r\n }\r\n\r\n const tokenData = await startUserOAuthFlow(scope, profile);\r\n await saveUserToken(tokenData, profile);\r\n\r\n output(\r\n {\r\n success: true,\r\n message: \"User OAuth login successful\",\r\n scope: tokenData.scope,\r\n profile,\r\n },\r\n opts\r\n );\r\n}\r\n\r\nasync function handleServiceAccountLogin(\r\n opts: Record<string, unknown>\r\n): Promise<void> {\r\n let clientId = opts.clientId as string | undefined;\r\n let clientSecret = opts.clientSecret as string | undefined;\r\n let serviceAccount = opts.serviceAccount as string | undefined;\r\n let privateKeyPath = opts.privateKey as string | undefined;\r\n let botId = opts.botId as string | undefined;\r\n const domainId = opts.domainId as string | undefined;\r\n const profile = opts.profile as string;\r\n\r\n if (!clientId) clientId = process.env[\"NWORKS_CLIENT_ID\"];\r\n if (!clientSecret) clientSecret = process.env[\"NWORKS_CLIENT_SECRET\"];\r\n if (!serviceAccount) serviceAccount = process.env[\"NWORKS_SERVICE_ACCOUNT\"];\r\n if (!privateKeyPath) privateKeyPath = process.env[\"NWORKS_PRIVATE_KEY_PATH\"];\r\n if (!botId) botId = process.env[\"NWORKS_BOT_ID\"];\r\n\r\n if (process.stdin.isTTY) {\r\n if (!clientId) clientId = await prompt(\"Client ID: \");\r\n if (!clientSecret) clientSecret = await prompt(\"Client Secret: \");\r\n if (!serviceAccount)\r\n serviceAccount = await prompt(\"Service Account: \");\r\n if (!privateKeyPath)\r\n privateKeyPath = await prompt(\"Private Key Path: \");\r\n if (!botId) botId = await prompt(\"Bot ID: \");\r\n }\r\n\r\n if (!clientId || !clientSecret || !serviceAccount || !privateKeyPath || !botId) {\r\n throw new Error(\r\n \"Missing required fields. Use flags, environment variables, or run interactively.\"\r\n );\r\n }\r\n\r\n if (!existsSync(privateKeyPath)) {\r\n throw new Error(`Private key file not found: ${privateKeyPath}`);\r\n }\r\n\r\n await readFile(privateKeyPath, \"utf-8\");\r\n\r\n const creds: Credentials = {\r\n clientId,\r\n clientSecret,\r\n serviceAccount,\r\n privateKeyPath,\r\n botId,\r\n domainId,\r\n };\r\n\r\n await saveCredentials(creds, profile);\r\n\r\n await refreshToken(profile);\r\n\r\n output(\r\n { success: true, message: `Logged in as ${serviceAccount}`, profile },\r\n opts\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","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 } 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 { 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","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 { Command } from \"commander\";\r\nimport { clearCredentials } from \"../auth/config.js\";\r\nimport { output } from \"../output/format.js\";\r\nimport { cliError } from \"../output/cli-error.js\";\r\n\r\nexport const logoutCommand = new Command(\"logout\")\r\n .description(\"Remove stored credentials and tokens\")\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 profile = opts.profile as string;\r\n await clearCredentials(profile);\r\n output({ success: true, message: `Logged out (profile: ${profile})` }, opts);\r\n } catch (err) {\r\n cliError(err, opts);\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_login_user tool로 다시 브라우저 로그인하세요. 그래도 안 되면 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 필요, Client Secret은 환경변수 NWORKS_CLIENT_SECRET에서 읽음). 환경변수가 없으면 사용자에게 MCP 설정 파일의 env 필드에 NWORKS_CLIENT_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 { Command } from \"commander\";\r\nimport { loadCredentials, loadToken } from \"../auth/config.js\";\r\nimport { output } from \"../output/format.js\";\r\nimport { cliError } from \"../output/cli-error.js\";\r\n\r\nexport const whoamiCommand = new Command(\"whoami\")\r\n .description(\"Show current authentication status\")\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 profile = opts.profile as string;\r\n const creds = await loadCredentials(profile);\r\n const token = await loadToken(profile);\r\n\r\n const expiresAt = token ? token.expiresAt : null;\r\n const isValid =\r\n typeof expiresAt === \"number\" && !isNaN(expiresAt)\r\n ? expiresAt > Date.now() / 1000\r\n : false;\r\n\r\n let tokenExpiresAt = \"(no token)\";\r\n if (typeof expiresAt === \"number\" && !isNaN(expiresAt) && expiresAt > 0) {\r\n tokenExpiresAt = new Date(expiresAt * 1000).toISOString();\r\n }\r\n\r\n output(\r\n {\r\n profile,\r\n serviceAccount: creds.serviceAccount ?? \"(not set)\",\r\n clientId: creds.clientId,\r\n botId: creds.botId ?? \"(not set)\",\r\n domainId: creds.domainId ?? \"(not set)\",\r\n tokenValid: isValid,\r\n tokenExpiresAt,\r\n },\r\n opts\r\n );\r\n } catch (err) {\r\n cliError(err, opts);\r\n }\r\n });\r\n","import { Command } from \"commander\";\r\nimport * as messageApi from \"../api/message.js\";\r\nimport { output } from \"../output/format.js\";\r\nimport { cliError } from \"../output/cli-error.js\";\r\n\r\nconst sendCommand = new Command(\"send\")\r\n .description(\"Send a message to a user or channel\")\r\n .option(\"--to <userId>\", \"Recipient user ID\")\r\n .option(\"--channel <channelId>\", \"Channel ID\")\r\n .requiredOption(\"--text <text>\", \"Message text\")\r\n .option(\"--type <type>\", \"Message type: text, button, list\", \"text\")\r\n .option(\"--actions <json>\", \"Button actions JSON (type=button)\")\r\n .option(\"--elements <json>\", \"List elements JSON (type=list)\")\r\n .option(\"--profile <name>\", \"Profile name\", \"default\")\r\n .option(\"--json\", \"JSON output\")\r\n .option(\"--dry-run\", \"Print request without sending\")\r\n .action(async (opts) => {\r\n try {\r\n if (!opts.to && !opts.channel) {\r\n throw new Error(\"Either --to or --channel is required.\");\r\n }\r\n\r\n const sendOpts: messageApi.SendOptions = {\r\n to: opts.to as string | undefined,\r\n channel: opts.channel as string | undefined,\r\n text: opts.text as string,\r\n type: opts.type as messageApi.MessageType,\r\n actions: opts.actions as string | undefined,\r\n elements: opts.elements as string | undefined,\r\n profile: opts.profile as string,\r\n };\r\n\r\n if (opts.dryRun) {\r\n output({ dryRun: true, request: sendOpts }, opts);\r\n return;\r\n }\r\n\r\n const result = await messageApi.send(sendOpts);\r\n output(result, opts);\r\n } catch (err) {\r\n cliError(err, opts);\r\n }\r\n });\r\n\r\nconst membersCommand = new Command(\"members\")\r\n .description(\"List members of a channel\")\r\n .requiredOption(\"--channel <channelId>\", \"Channel ID\")\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 result = await messageApi.listMembers(\r\n opts.channel as string,\r\n opts.profile as string\r\n );\r\n output(result, opts);\r\n } catch (err) {\r\n cliError(err, opts);\r\n }\r\n });\r\n\r\nexport const messageCommand = new Command(\"message\")\r\n .description(\"Bot message operations\")\r\n .addCommand(sendCommand)\r\n .addCommand(membersCommand);\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 { Command } from \"commander\";\r\nimport * as directoryApi from \"../api/directory.js\";\r\nimport { output } from \"../output/format.js\";\r\nimport { cliError } from \"../output/cli-error.js\";\r\n\r\nconst membersCommand = new Command(\"members\")\r\n .description(\"List organization members (requires directory.read scope)\")\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 result = await directoryApi.listUsers(opts.profile as string);\r\n const formatted = {\r\n users: result.users.map((u) => ({\r\n userId: u.userId,\r\n userName: [u.userName?.lastName, u.userName?.firstName]\r\n .filter(Boolean)\r\n .join(\" \") || \"\",\r\n email: u.email ?? \"\",\r\n cellPhone: (u as unknown as Record<string, unknown>).cellPhone as string ?? \"\",\r\n organization:\r\n u.organizations\r\n ?.find((o) => o.primary)?.organizationName ??\r\n u.organizations?.[0]?.organizationName ??\r\n \"\",\r\n })),\r\n };\r\n output(formatted, opts);\r\n } catch (err) {\r\n cliError(err, opts);\r\n }\r\n });\r\n\r\nexport const directoryCommand = new Command(\"directory\")\r\n .description(\"Directory (organization) operations\")\r\n .addCommand(membersCommand);\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 { Command } from \"commander\";\nimport * as calendarApi from \"../api/calendar.js\";\nimport { output } from \"../output/format.js\";\nimport { cliError } from \"../output/cli-error.js\";\n\nfunction todayRange(): { from: string; until: string } {\n const now = new Date();\n const yyyy = now.getFullYear();\n const mm = String(now.getMonth() + 1).padStart(2, \"0\");\n const dd = String(now.getDate()).padStart(2, \"0\");\n return {\n from: `${yyyy}-${mm}-${dd}T00:00:00+09:00`,\n until: `${yyyy}-${mm}-${dd}T23:59:59+09:00`,\n };\n}\n\nconst listCommand = new Command(\"list\")\n .description(\"List calendar events (requires User OAuth with calendar.read or calendar scope)\")\n .option(\"--user <userId>\", \"Target user ID (default: me)\")\n .option(\"--from <dateTime>\", \"Start (YYYY-MM-DDThh:mm:ss+09:00, default: today 00:00)\")\n .option(\"--until <dateTime>\", \"End (YYYY-MM-DDThh:mm:ss+09:00, default: today 23:59)\")\n .option(\"--profile <name>\", \"Profile name\", \"default\")\n .option(\"--json\", \"JSON output\")\n .action(async (opts) => {\n try {\n const defaults = todayRange();\n const from = (opts.from as string | undefined) ?? defaults.from;\n const until = (opts.until as string | undefined) ?? defaults.until;\n const userId = (opts.user as string | undefined) ?? \"me\";\n\n const result = await calendarApi.listEvents(\n from,\n until,\n userId,\n opts.profile as string\n );\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\n ? `${c.start.dateTime} (${c.start.timeZone ?? \"\"})`\n : c.start.date ?? \"\",\n end: c.end.dateTime\n ? `${c.end.dateTime} (${c.end.timeZone ?? \"\"})`\n : c.end.date ?? \"\",\n location: c.location ?? \"\",\n }))\n );\n\n output({ events, count: events.length }, opts);\n } catch (err) {\n cliError(err, opts, \"calendar\");\n }\n });\n\nconst createCommand = new Command(\"create\")\n .description(\"Create a calendar event (requires User OAuth with calendar scope)\")\n .requiredOption(\"--title <title>\", \"Event title (summary)\")\n .requiredOption(\"--start <dateTime>\", \"Start (YYYY-MM-DDThh:mm:ss)\")\n .requiredOption(\"--end <dateTime>\", \"End (YYYY-MM-DDThh:mm:ss)\")\n .option(\"--tz <timeZone>\", \"Time zone (default: Asia/Seoul)\", \"Asia/Seoul\")\n .option(\"--description <text>\", \"Event description\")\n .option(\"--location <place>\", \"Event location\")\n .option(\"--attendees <emails>\", \"Attendee emails (comma-separated)\")\n .option(\"--notify\", \"Send notification to attendees\")\n .option(\"--user <userId>\", \"Target user ID (default: me)\")\n .option(\"--profile <name>\", \"Profile name\", \"default\")\n .option(\"--json\", \"JSON output\")\n .action(async (opts) => {\n try {\n const attendees = opts.attendees\n ? (opts.attendees as string).split(\",\").map((e: string) => ({ email: e.trim() }))\n : undefined;\n\n const result = await calendarApi.createEvent({\n summary: opts.title as string,\n start: opts.start as string,\n end: opts.end as string,\n timeZone: opts.tz as string,\n description: opts.description as string | undefined,\n location: opts.location as string | undefined,\n attendees,\n sendNotification: (opts.notify as boolean | undefined) ?? false,\n userId: (opts.user as string | undefined) ?? \"me\",\n profile: opts.profile as string,\n });\n\n const event = result.eventComponents?.[0];\n const fmt = (t?: { dateTime?: string; timeZone?: string }) =>\n t?.dateTime ? `${t.dateTime} (${t.timeZone ?? \"\"})` : \"\";\n output(\n {\n success: true,\n eventId: event?.eventId,\n summary: event?.summary,\n start: fmt(event?.start),\n end: fmt(event?.end),\n },\n opts\n );\n } catch (err) {\n cliError(err, opts, \"calendar\");\n }\n });\n\nconst updateCommand = new Command(\"update\")\n .description(\"Update a calendar event (requires User OAuth with calendar scope)\")\n .requiredOption(\"--id <eventId>\", \"Event ID\")\n .option(\"--title <title>\", \"New title (summary)\")\n .option(\"--start <dateTime>\", \"New start (YYYY-MM-DDThh:mm:ss)\")\n .option(\"--end <dateTime>\", \"New end (YYYY-MM-DDThh:mm:ss)\")\n .option(\"--tz <timeZone>\", \"Time zone (default: Asia/Seoul)\", \"Asia/Seoul\")\n .option(\"--description <text>\", \"New description\")\n .option(\"--location <place>\", \"New location\")\n .option(\"--attendees <emails>\", \"Attendee emails (comma-separated)\")\n .option(\"--notify\", \"Send notification to attendees\")\n .option(\"--user <userId>\", \"Target user ID (default: me)\")\n .option(\"--profile <name>\", \"Profile name\", \"default\")\n .option(\"--json\", \"JSON output\")\n .action(async (opts) => {\n try {\n const hasUpdate =\n opts.title || opts.start || opts.end || opts.description || opts.location || opts.attendees;\n if (!hasUpdate) {\n throw new Error(\"Specify at least one of: --title, --start, --end, --description, --location, --attendees\");\n }\n\n const attendees = opts.attendees\n ? (opts.attendees as string).split(\",\").map((e: string) => ({ email: e.trim() }))\n : undefined;\n\n await calendarApi.updateEvent({\n eventId: opts.id as string,\n summary: opts.title as string | undefined,\n start: opts.start as string | undefined,\n end: opts.end as string | undefined,\n timeZone: opts.tz as string,\n description: opts.description as string | undefined,\n location: opts.location as string | undefined,\n attendees,\n sendNotification: (opts.notify as boolean | undefined) ?? false,\n userId: (opts.user as string | undefined) ?? \"me\",\n profile: opts.profile as string,\n });\n\n output(\n { success: true, eventId: opts.id, message: \"Event updated\" },\n opts\n );\n } catch (err) {\n cliError(err, opts, \"calendar\");\n }\n });\n\nconst deleteCommand = new Command(\"delete\")\n .description(\"Delete a calendar event (requires User OAuth with calendar scope)\")\n .requiredOption(\"--id <eventId>\", \"Event ID\")\n .option(\"--notify\", \"Send notification to attendees\")\n .option(\"--user <userId>\", \"Target user ID (default: me)\")\n .option(\"--profile <name>\", \"Profile name\", \"default\")\n .option(\"--json\", \"JSON output\")\n .action(async (opts) => {\n try {\n await calendarApi.deleteEvent(\n opts.id as string,\n (opts.user as string | undefined) ?? \"me\",\n (opts.notify as boolean | undefined) ?? false,\n opts.profile as string\n );\n output({ success: true, eventId: opts.id, message: \"Event deleted\" }, opts);\n } catch (err) {\n cliError(err, opts, \"calendar\");\n }\n });\n\nexport const calendarCommand = new Command(\"calendar\")\n .description(\"Calendar operations (requires User OAuth)\")\n .addCommand(listCommand)\n .addCommand(createCommand)\n .addCommand(updateCommand)\n .addCommand(deleteCommand);\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 { 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 { writeFile } from \"node:fs/promises\";\r\nimport { join } from \"node:path\";\r\nimport { Command } from \"commander\";\r\nimport * as driveApi from \"../api/drive.js\";\r\nimport { output } from \"../output/format.js\";\r\nimport { cliError } from \"../output/cli-error.js\";\r\n\r\nconst listCommand = new Command(\"list\")\r\n .description(\"List files in Drive (requires User OAuth with file or file.read scope)\")\r\n .option(\"--user <userId>\", \"Target user ID (default: me)\")\r\n .option(\"--folder <folderId>\", \"Folder ID to list (default: root)\")\r\n .option(\"--count <n>\", \"Items per page (default: 20)\", \"20\")\r\n .option(\"--cursor <cursor>\", \"Pagination cursor\")\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 result = await driveApi.listFiles(\r\n (opts.user as string | undefined) ?? \"me\",\r\n opts.folder as string | undefined,\r\n parseInt(opts.count as string, 10),\r\n opts.cursor as string | undefined,\r\n opts.profile as string\r\n );\r\n\r\n const files = result.files.map((f) => ({\r\n name: f.fileName,\r\n type: f.fileType,\r\n size: f.fileSize,\r\n modified: f.modifiedTime,\r\n fileId: f.fileId,\r\n }));\r\n\r\n output(\r\n {\r\n files,\r\n count: files.length,\r\n nextCursor: result.responseMetaData?.nextCursor ?? null,\r\n },\r\n opts\r\n );\r\n } catch (err) {\r\n cliError(err, opts, \"drive\");\r\n }\r\n });\r\n\r\nconst uploadCommand = new Command(\"upload\")\r\n .description(\"Upload a file to Drive (requires User OAuth with file scope)\")\r\n .requiredOption(\"--file <path>\", \"Local file path to upload\")\r\n .option(\"--user <userId>\", \"Target user ID (default: me)\")\r\n .option(\"--folder <folderId>\", \"Destination folder ID (default: root)\")\r\n .option(\"--overwrite\", \"Overwrite if file exists\", false)\r\n .option(\"--profile <name>\", \"Profile name\", \"default\")\r\n .option(\"--json\", \"JSON output\")\r\n .option(\"--dry-run\", \"Print request without uploading\")\r\n .action(async (opts) => {\r\n try {\r\n if (opts.dryRun) {\r\n output(\r\n {\r\n dryRun: true,\r\n request: {\r\n file: opts.file,\r\n user: opts.user ?? \"me\",\r\n folder: opts.folder ?? \"(root)\",\r\n overwrite: opts.overwrite,\r\n },\r\n },\r\n opts\r\n );\r\n return;\r\n }\r\n\r\n const result = await driveApi.uploadFile(\r\n opts.file as string,\r\n (opts.user as string | undefined) ?? \"me\",\r\n opts.folder as string | undefined,\r\n opts.overwrite as boolean,\r\n opts.profile as string\r\n );\r\n\r\n output(\r\n {\r\n success: true,\r\n fileId: result.fileId,\r\n fileName: result.fileName,\r\n fileSize: result.fileSize,\r\n filePath: result.filePath,\r\n fileType: result.fileType,\r\n },\r\n opts\r\n );\r\n } catch (err) {\r\n cliError(err, opts, \"drive\");\r\n }\r\n });\r\n\r\nconst downloadCommand = new Command(\"download\")\r\n .description(\"Download a file from Drive (requires User OAuth with file or file.read scope)\")\r\n .requiredOption(\"--file-id <fileId>\", \"File ID to download\")\r\n .option(\"--out <path>\", \"Output directory (default: current directory)\")\r\n .option(\"--name <filename>\", \"Output filename (default: original name)\")\r\n .option(\"--user <userId>\", \"Target user ID (default: me)\")\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 result = await driveApi.downloadFile(\r\n opts.fileId as string,\r\n (opts.user as string | undefined) ?? \"me\",\r\n opts.profile as string\r\n );\r\n\r\n const fileName =\r\n (opts.name as string | undefined) ?? result.fileName ?? opts.fileId as string;\r\n const outDir = (opts.out as string | undefined) ?? process.cwd();\r\n const outPath = join(outDir, fileName);\r\n\r\n await writeFile(outPath, result.buffer);\r\n\r\n output(\r\n {\r\n success: true,\r\n fileName,\r\n path: outPath,\r\n size: result.buffer.length,\r\n },\r\n opts\r\n );\r\n } catch (err) {\r\n cliError(err, opts, \"drive\");\r\n }\r\n });\r\n\r\nexport const driveCommand = new Command(\"drive\")\r\n .description(\"Drive operations (requires User OAuth with file scope)\")\r\n .addCommand(listCommand)\r\n .addCommand(uploadCommand)\r\n .addCommand(downloadCommand);\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 { Command } from \"commander\";\r\nimport * as mailApi from \"../api/mail.js\";\r\nimport { output } from \"../output/format.js\";\r\nimport { cliError } from \"../output/cli-error.js\";\r\n\r\nconst sendCommand = new Command(\"send\")\r\n .description(\"Send a mail (requires User OAuth with mail scope)\")\r\n .requiredOption(\"--to <emails>\", \"Recipient email addresses (separate with ;)\")\r\n .requiredOption(\"--subject <subject>\", \"Mail subject\")\r\n .option(\"--body <body>\", \"Mail body content\")\r\n .option(\"--cc <emails>\", \"CC email addresses (separate with ;)\")\r\n .option(\"--bcc <emails>\", \"BCC email addresses (separate with ;)\")\r\n .option(\"--content-type <type>\", \"Body format: html or text\", \"html\")\r\n .option(\"--user <userId>\", \"Sender user ID (default: me)\")\r\n .option(\"--profile <name>\", \"Profile name\", \"default\")\r\n .option(\"--json\", \"JSON output\")\r\n .option(\"--dry-run\", \"Print request without sending\")\r\n .action(async (opts) => {\r\n try {\r\n const sendOpts: mailApi.SendMailOptions = {\r\n to: opts.to as string,\r\n subject: opts.subject as string,\r\n body: opts.body as string | undefined,\r\n cc: opts.cc as string | undefined,\r\n bcc: opts.bcc as string | undefined,\r\n contentType: opts.contentType as \"html\" | \"text\",\r\n userId: (opts.user as string | undefined) ?? \"me\",\r\n profile: opts.profile as string,\r\n };\r\n\r\n if (opts.dryRun) {\r\n output({ dryRun: true, request: sendOpts }, opts);\r\n return;\r\n }\r\n\r\n await mailApi.sendMail(sendOpts);\r\n output({ success: true, message: \"Mail sent (async)\" }, opts);\r\n } catch (err) {\r\n cliError(err, opts, \"mail\");\r\n }\r\n });\r\n\r\nconst listCommand = new Command(\"list\")\r\n .description(\"List mails in a folder (requires User OAuth with mail or mail.read scope)\")\r\n .option(\"--folder <folderId>\", \"Folder ID (default: 0 = inbox)\", \"0\")\r\n .option(\"--count <n>\", \"Items per page (default: 30)\", \"30\")\r\n .option(\"--cursor <cursor>\", \"Pagination cursor\")\r\n .option(\"--unread\", \"Show unread mails only\", false)\r\n .option(\"--user <userId>\", \"Target user ID (default: me)\")\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 result = await mailApi.listMails(\r\n parseInt(opts.folder as string, 10),\r\n (opts.user as string | undefined) ?? \"me\",\r\n parseInt(opts.count as string, 10),\r\n opts.cursor as string | undefined,\r\n opts.unread as boolean,\r\n opts.profile as string\r\n );\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\r\n output(\r\n {\r\n mails,\r\n count: mails.length,\r\n totalCount: result.totalCount,\r\n unreadCount: result.unreadCount,\r\n folderName: result.folderName,\r\n nextCursor: result.responseMetaData?.nextCursor ?? null,\r\n },\r\n opts\r\n );\r\n } catch (err) {\r\n cliError(err, opts, \"mail\");\r\n }\r\n });\r\n\r\nconst readCommand = new Command(\"read\")\r\n .description(\"Read a specific mail (requires User OAuth with mail or mail.read scope)\")\r\n .requiredOption(\"--id <mailId>\", \"Mail ID\")\r\n .option(\"--user <userId>\", \"Target user ID (default: me)\")\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 result = await mailApi.readMail(\r\n parseInt(opts.id as string, 10),\r\n (opts.user as string | undefined) ?? \"me\",\r\n opts.profile as string\r\n );\r\n\r\n const mail = result.mail;\r\n output(\r\n {\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 opts\r\n );\r\n } catch (err) {\r\n cliError(err, opts, \"mail\");\r\n }\r\n });\r\n\r\nexport const mailCommand = new Command(\"mail\")\r\n .description(\"Mail operations (requires User OAuth with mail scope)\")\r\n .addCommand(sendCommand)\r\n .addCommand(listCommand)\r\n .addCommand(readCommand);\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 { Command } from \"commander\";\r\nimport * as taskApi from \"../api/task.js\";\r\nimport { output } from \"../output/format.js\";\r\nimport { cliError } from \"../output/cli-error.js\";\r\n\r\nconst listCommand = new Command(\"list\")\r\n .description(\"List tasks (requires User OAuth with task or task.read scope)\")\r\n .option(\"--category <categoryId>\", \"Category ID (default: default)\", \"default\")\r\n .option(\"--status <status>\", \"Filter: TODO or ALL (default: ALL)\", \"ALL\")\r\n .option(\"--count <n>\", \"Items per page (default: 50)\", \"50\")\r\n .option(\"--cursor <cursor>\", \"Pagination cursor\")\r\n .option(\"--user <userId>\", \"Target user ID (default: me)\")\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 result = await taskApi.listTasks(\r\n opts.category as string,\r\n (opts.user as string | undefined) ?? \"me\",\r\n parseInt(opts.count as string, 10),\r\n opts.cursor as string | undefined,\r\n opts.status as \"TODO\" | \"ALL\",\r\n opts.profile as string\r\n );\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\r\n output(\r\n {\r\n tasks,\r\n count: tasks.length,\r\n nextCursor: result.responseMetaData?.nextCursor ?? null,\r\n },\r\n opts\r\n );\r\n } catch (err) {\r\n cliError(err, opts, \"task\");\r\n }\r\n });\r\n\r\nconst createCommand = new Command(\"create\")\r\n .description(\"Create a task (requires User OAuth with task scope)\")\r\n .requiredOption(\"--title <title>\", \"Task title\")\r\n .option(\"--body <content>\", \"Task content/description\")\r\n .option(\"--due <date>\", \"Due date (YYYY-MM-DD)\")\r\n .option(\"--category <categoryId>\", \"Category ID\")\r\n .option(\"--assignee <userIds>\", \"Assignee user IDs (comma-separated)\")\r\n .option(\"--user <userId>\", \"Creator user ID (default: me)\")\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 assigneeIds = opts.assignee\r\n ? (opts.assignee as string).split(\",\").map((s: string) => s.trim())\r\n : undefined;\r\n\r\n const result = await taskApi.createTask({\r\n title: opts.title as string,\r\n content: opts.body as string | undefined,\r\n dueDate: opts.due as string | undefined,\r\n categoryId: opts.category as string | undefined,\r\n assigneeIds,\r\n userId: (opts.user as string | undefined) ?? \"me\",\r\n profile: opts.profile as string,\r\n });\r\n\r\n output(\r\n {\r\n success: true,\r\n taskId: result.taskId,\r\n title: result.title,\r\n status: result.status,\r\n dueDate: result.dueDate,\r\n },\r\n opts\r\n );\r\n } catch (err) {\r\n cliError(err, opts, \"task\");\r\n }\r\n });\r\n\r\nconst updateCommand = new Command(\"update\")\r\n .description(\"Update a task (requires User OAuth with task scope)\")\r\n .requiredOption(\"--id <taskId>\", \"Task ID\")\r\n .option(\"--title <title>\", \"New title\")\r\n .option(\"--body <content>\", \"New content\")\r\n .option(\"--due <date>\", \"New due date (YYYY-MM-DD)\")\r\n .option(\"--status <status>\", \"Set status: done or todo\")\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 profile = opts.profile as string;\r\n const taskId = opts.id as string;\r\n const status = opts.status as string | undefined;\r\n\r\n if (status) {\r\n if (status.toLowerCase() === \"done\") {\r\n await taskApi.completeTask(taskId, profile);\r\n } else if (status.toLowerCase() === \"todo\") {\r\n await taskApi.incompleteTask(taskId, profile);\r\n } else {\r\n throw new Error(\"Invalid status. Use 'done' or 'todo'.\");\r\n }\r\n }\r\n\r\n const hasFieldUpdate = opts.title || opts.body || opts.due;\r\n if (hasFieldUpdate) {\r\n const result = await taskApi.updateTask({\r\n taskId,\r\n title: opts.title as string | undefined,\r\n content: opts.body as string | undefined,\r\n dueDate: opts.due as string | undefined,\r\n profile,\r\n });\r\n output(\r\n {\r\n success: true,\r\n taskId: result.taskId,\r\n title: result.title,\r\n status: result.status,\r\n dueDate: result.dueDate,\r\n },\r\n opts\r\n );\r\n } else if (status) {\r\n output(\r\n { success: true, taskId, status: status.toLowerCase() === \"done\" ? \"DONE\" : \"TODO\" },\r\n opts\r\n );\r\n } else {\r\n throw new Error(\"Specify at least one of: --title, --body, --due, --status\");\r\n }\r\n } catch (err) {\r\n cliError(err, opts, \"task\");\r\n }\r\n });\r\n\r\nconst deleteCommand = new Command(\"delete\")\r\n .description(\"Delete a task (requires User OAuth with task scope)\")\r\n .requiredOption(\"--id <taskId>\", \"Task ID\")\r\n .option(\"--profile <name>\", \"Profile name\", \"default\")\r\n .option(\"--json\", \"JSON output\")\r\n .action(async (opts) => {\r\n try {\r\n await taskApi.deleteTask(\r\n opts.id as string,\r\n opts.profile as string\r\n );\r\n output({ success: true, taskId: opts.id, message: \"Task deleted\" }, opts);\r\n } catch (err) {\r\n cliError(err, opts, \"task\");\r\n }\r\n });\r\n\r\nexport const taskCommand = new Command(\"task\")\r\n .description(\"Task operations (requires User OAuth with task scope)\")\r\n .addCommand(listCommand)\r\n .addCommand(createCommand)\r\n .addCommand(updateCommand)\r\n .addCommand(deleteCommand);\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 { Command } from \"commander\";\r\nimport * as boardApi from \"../api/board.js\";\r\nimport { output } from \"../output/format.js\";\r\nimport { cliError } from \"../output/cli-error.js\";\r\n\r\nconst listCommand = new Command(\"list\")\r\n .description(\"List boards (requires User OAuth with board or board.read scope)\")\r\n .option(\"--count <n>\", \"Items per page (default: 20)\", \"20\")\r\n .option(\"--cursor <cursor>\", \"Pagination cursor\")\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 result = await boardApi.listBoards(\r\n parseInt(opts.count as string, 10),\r\n opts.cursor as string | undefined,\r\n opts.profile as string\r\n );\r\n\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\r\n output(\r\n { boards, count: boards.length, nextCursor: result.responseMetaData?.nextCursor ?? null },\r\n opts\r\n );\r\n } catch (err) {\r\n cliError(err, opts, \"board\");\r\n }\r\n });\r\n\r\nconst postsCommand = new Command(\"posts\")\r\n .description(\"List posts in a board (requires User OAuth with board or board.read scope)\")\r\n .requiredOption(\"--board <boardId>\", \"Board ID\")\r\n .option(\"--count <n>\", \"Items per page (default: 20)\", \"20\")\r\n .option(\"--cursor <cursor>\", \"Pagination cursor\")\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 result = await boardApi.listPosts(\r\n opts.board as string,\r\n parseInt(opts.count as string, 10),\r\n opts.cursor as string | undefined,\r\n opts.profile as string\r\n );\r\n\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\r\n output(\r\n { posts, count: posts.length, nextCursor: result.responseMetaData?.nextCursor ?? null },\r\n opts\r\n );\r\n } catch (err) {\r\n cliError(err, opts, \"board\");\r\n }\r\n });\r\n\r\nconst readCommand = new Command(\"read\")\r\n .description(\"Read a post detail (requires User OAuth with board or board.read scope)\")\r\n .requiredOption(\"--board <boardId>\", \"Board ID\")\r\n .requiredOption(\"--post <postId>\", \"Post ID\")\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 post = await boardApi.readPost(\r\n opts.board as string,\r\n opts.post as string,\r\n opts.profile as string\r\n );\r\n\r\n output(\r\n {\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 opts\r\n );\r\n } catch (err) {\r\n cliError(err, opts, \"board\");\r\n }\r\n });\r\n\r\nconst createCommand = new Command(\"create\")\r\n .description(\"Create a post in a board (requires User OAuth with board scope)\")\r\n .requiredOption(\"--board <boardId>\", \"Board ID\")\r\n .requiredOption(\"--title <title>\", \"Post title\")\r\n .option(\"--body <text>\", \"Post body\")\r\n .option(\"--no-comment\", \"Disable comments\")\r\n .option(\"--notify\", \"Send notification\")\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 post = await boardApi.createPost({\r\n boardId: opts.board as string,\r\n title: opts.title as string,\r\n body: opts.body as string | undefined,\r\n enableComment: opts.comment as boolean,\r\n sendNotifications: (opts.notify as boolean | undefined) ?? false,\r\n profile: opts.profile as string,\r\n });\r\n\r\n output(\r\n {\r\n success: true,\r\n postId: post.postId,\r\n boardId: post.boardId,\r\n title: post.title,\r\n },\r\n opts\r\n );\r\n } catch (err) {\r\n cliError(err, opts, \"board\");\r\n }\r\n });\r\n\r\nexport const boardCommand = new Command(\"board\")\r\n .description(\"Board operations (requires User OAuth)\")\r\n .addCommand(listCommand)\r\n .addCommand(postsCommand)\r\n .addCommand(readCommand)\r\n .addCommand(createCommand);\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 { startMcpServer } from \"../mcp/server.js\";\r\n\r\nexport const mcpCommand = new Command(\"mcp\")\r\n .description(\"Start MCP server (stdio transport)\")\r\n .option(\"--list-tools\", \"List available MCP tools\")\r\n .action(async (opts) => {\r\n if (opts.listTools) {\r\n console.log(\"nworks_message_send — Send message to user or channel\");\r\n console.log(\"nworks_message_members — List channel members\");\r\n console.log(\"nworks_directory_members — List organization members\");\r\n console.log(\"nworks_calendar_list — List calendar events (User OAuth)\");\r\n console.log(\"nworks_whoami — Show auth status\");\r\n return;\r\n }\r\n\r\n await startMcpServer();\r\n });\r\n","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 인증 정보를 설정합니다.\r\n\r\n■ 사전 준비 (사용자가 직접 해야 함):\r\n 1. https://dev.worksmobile.com 에서 앱 생성 후 Client ID와 Client Secret을 발급받습니다.\r\n 2. MCP 설정 파일(예: claude_desktop_config.json)의 nworks 서버에 env 필드를 추가합니다:\r\n { \"env\": { \"NWORKS_CLIENT_SECRET\": \"<발급받은 Client Secret>\" } }\r\n 3. MCP 클라이언트(예: Claude Desktop)를 재시작합니다.\r\n\r\n■ 이 tool의 역할:\r\n - clientId(필수)와 serviceAccount, botId, domainId(선택)를 파라미터로 받아 저장합니다.\r\n - Client Secret은 보안을 위해 파라미터로 받지 않으며, 환경변수 NWORKS_CLIENT_SECRET에서 자동으로 읽습니다.\r\n - Service Account 사용 시 환경변수 NWORKS_PRIVATE_KEY_PATH도 필요합니다.\r\n\r\n■ 설정 후 다음 단계:\r\n - 캘린더/메일/드라이브/할일/게시판 → nworks_login_user tool로 브라우저 로그인 필요\r\n - 메시지/구성원조회 → Service Account 인증 (serviceAccount + botId + NWORKS_PRIVATE_KEY_PATH)\r\n\r\n■ 환경변수 NWORKS_CLIENT_SECRET이 없으면 이 tool은 실패합니다. 실패 시 사용자에게 위 사전 준비 단계를 안내하세요.\r\n\r\nOAuth 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 userAction: [\r\n \"1. https://dev.worksmobile.com 에서 앱의 Client Secret을 확인합니다.\",\r\n '2. MCP 설정 파일(예: claude_desktop_config.json)을 열고, nworks 서버 설정에 다음을 추가합니다:',\r\n ' \"env\": { \"NWORKS_CLIENT_SECRET\": \"<Client Secret>\" }',\r\n \"3. MCP 클라이언트(예: Claude Desktop)를 재시작합니다.\",\r\n \"4. 재시작 후 다시 시도해주세요.\",\r\n ],\r\n configExample: '{ \"mcpServers\": { \"nworks\": { \"command\": \"npx\", \"args\": [\"-y\", \"nworks\", \"mcp\"], \"env\": { \"NWORKS_CLIENT_SECRET\": \"<Client Secret>\" } } } }',\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 파일 경로가 필요합니다. 사용자에게 안내하세요: (1) Developer Console(https://dev.worksmobile.com)에서 Private Key를 다운로드 (2) MCP 설정 파일의 env에 NWORKS_PRIVATE_KEY_PATH를 추가 (예: \\\"NWORKS_PRIVATE_KEY_PATH\\\": \\\"C:/keys/private.key\\\") (3) MCP 클라이언트 재시작\");\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로 재설정 후 nworks_login_user로 브라우저 로그인하세요.\",\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","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: \"인증 정보 없음. CLI: `nworks login --user` / MCP: nworks_setup tool 사용 (환경변수 NWORKS_CLIENT_SECRET 필요)\" });\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"],"mappings":"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","names":["Command","readFile","existsSync","readFile","readFile","AUTH_URL","refreshToken","existsSync","readFile","Command","Command","Command","Command","Command","Command","Command","membersCommand","Command","Command","BASE_URL","Command","writeFile","join","Command","readFile","BASE_URL","authedFetch","handleError","readFile","listCommand","Command","join","writeFile","Command","BASE_URL","authedFetch","handleError","sendCommand","Command","listCommand","Command","BASE_URL","authedFetch","handleError","BASE_URL","authedFetch","handleError","BASE_URL","authedFetch","handleError","listCommand","Command","createCommand","updateCommand","deleteCommand","Command","BASE_URL","authedFetch","handleError","listCommand","Command","readCommand","createCommand","Command","Command","existsSync","readFile","existsSync","readFile","Command","writeFile","join","Command","require","Command"]}
|