nworks 0.6.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +178 -127
- package/dist/index.js +419 -28
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +275 -18
- package/dist/mcp.js.map +1 -1
- package/package.json +8 -5
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ var __export = (target, all) => {
|
|
|
7
7
|
|
|
8
8
|
// src/index.ts
|
|
9
9
|
import { createRequire } from "module";
|
|
10
|
-
import { Command as
|
|
10
|
+
import { Command as Command12 } from "commander";
|
|
11
11
|
|
|
12
12
|
// src/commands/login.ts
|
|
13
13
|
import { Command } from "commander";
|
|
@@ -52,20 +52,15 @@ async function ensureConfigDir() {
|
|
|
52
52
|
function getCredentialsFromEnv() {
|
|
53
53
|
const clientId = process.env["NWORKS_CLIENT_ID"];
|
|
54
54
|
const clientSecret = process.env["NWORKS_CLIENT_SECRET"];
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
botId,
|
|
65
|
-
domainId: process.env["NWORKS_DOMAIN_ID"]
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
return null;
|
|
55
|
+
if (!clientId || !clientSecret) return null;
|
|
56
|
+
return {
|
|
57
|
+
clientId,
|
|
58
|
+
clientSecret,
|
|
59
|
+
serviceAccount: process.env["NWORKS_SERVICE_ACCOUNT"],
|
|
60
|
+
privateKeyPath: process.env["NWORKS_PRIVATE_KEY_PATH"],
|
|
61
|
+
botId: process.env["NWORKS_BOT_ID"],
|
|
62
|
+
domainId: process.env["NWORKS_DOMAIN_ID"]
|
|
63
|
+
};
|
|
69
64
|
}
|
|
70
65
|
async function loadCredentials(profile = "default") {
|
|
71
66
|
const envCreds = getCredentialsFromEnv();
|
|
@@ -166,6 +161,11 @@ async function clearCredentials(profile = "default") {
|
|
|
166
161
|
import { readFile as readFile2 } from "fs/promises";
|
|
167
162
|
import jwt from "jsonwebtoken";
|
|
168
163
|
async function createJWT(creds) {
|
|
164
|
+
if (!creds.serviceAccount || !creds.privateKeyPath) {
|
|
165
|
+
throw new AuthError(
|
|
166
|
+
"Service Account credentials required for bot authentication.\nRun `nworks login` with --service-account and --private-key flags."
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
169
|
const privateKey = await readFile2(creds.privateKeyPath, "utf-8");
|
|
170
170
|
const now = Math.floor(Date.now() / 1e3);
|
|
171
171
|
const payload = {
|
|
@@ -232,7 +232,7 @@ function buildAuthorizeUrl(clientId, scope, state) {
|
|
|
232
232
|
});
|
|
233
233
|
return `${AUTH_URL2}?${params.toString()}`;
|
|
234
234
|
}
|
|
235
|
-
async function startUserOAuthFlow(
|
|
235
|
+
async function startUserOAuthFlow(_scope, profile = "default") {
|
|
236
236
|
const creds = await loadCredentials(profile);
|
|
237
237
|
const code = await waitForAuthCode();
|
|
238
238
|
return exchangeCodeForToken(code, creds.clientId, creds.clientSecret);
|
|
@@ -431,9 +431,31 @@ var loginCommand = new Command("login").description("Authenticate with NAVER WOR
|
|
|
431
431
|
}
|
|
432
432
|
});
|
|
433
433
|
async function handleUserLogin(scope, profile, opts) {
|
|
434
|
-
|
|
434
|
+
let clientId = opts.clientId;
|
|
435
|
+
let clientSecret = opts.clientSecret;
|
|
436
|
+
try {
|
|
437
|
+
const existing = await loadCredentials(profile);
|
|
438
|
+
if (!clientId) clientId = existing.clientId;
|
|
439
|
+
if (!clientSecret) clientSecret = existing.clientSecret;
|
|
440
|
+
} catch {
|
|
441
|
+
}
|
|
442
|
+
if (process.stdin.isTTY) {
|
|
443
|
+
if (!clientId) clientId = await prompt("Client ID: ");
|
|
444
|
+
if (!clientSecret) clientSecret = await prompt("Client Secret: ");
|
|
445
|
+
}
|
|
446
|
+
if (!clientId || !clientSecret) {
|
|
447
|
+
throw new Error(
|
|
448
|
+
"Client ID and Client Secret are required for User OAuth.\nUse --client-id and --client-secret flags, or set NWORKS_CLIENT_ID / NWORKS_CLIENT_SECRET env vars."
|
|
449
|
+
);
|
|
450
|
+
}
|
|
451
|
+
try {
|
|
452
|
+
const existing = await loadCredentials(profile);
|
|
453
|
+
await saveCredentials({ ...existing, clientId, clientSecret }, profile);
|
|
454
|
+
} catch {
|
|
455
|
+
await saveCredentials({ clientId, clientSecret }, profile);
|
|
456
|
+
}
|
|
435
457
|
const state = randomBytes(16).toString("hex");
|
|
436
|
-
const authorizeUrl = buildAuthorizeUrl(
|
|
458
|
+
const authorizeUrl = buildAuthorizeUrl(clientId, scope, state);
|
|
437
459
|
console.error(`
|
|
438
460
|
Opening browser for NAVER WORKS login...`);
|
|
439
461
|
console.error(`If the browser does not open, visit this URL:
|
|
@@ -463,6 +485,11 @@ async function handleServiceAccountLogin(opts) {
|
|
|
463
485
|
let botId = opts.botId;
|
|
464
486
|
const domainId = opts.domainId;
|
|
465
487
|
const profile = opts.profile;
|
|
488
|
+
if (!clientId) clientId = process.env["NWORKS_CLIENT_ID"];
|
|
489
|
+
if (!clientSecret) clientSecret = process.env["NWORKS_CLIENT_SECRET"];
|
|
490
|
+
if (!serviceAccount) serviceAccount = process.env["NWORKS_SERVICE_ACCOUNT"];
|
|
491
|
+
if (!privateKeyPath) privateKeyPath = process.env["NWORKS_PRIVATE_KEY_PATH"];
|
|
492
|
+
if (!botId) botId = process.env["NWORKS_BOT_ID"];
|
|
466
493
|
if (process.stdin.isTTY) {
|
|
467
494
|
if (!clientId) clientId = await prompt("Client ID: ");
|
|
468
495
|
if (!clientSecret) clientSecret = await prompt("Client Secret: ");
|
|
@@ -474,7 +501,7 @@ async function handleServiceAccountLogin(opts) {
|
|
|
474
501
|
}
|
|
475
502
|
if (!clientId || !clientSecret || !serviceAccount || !privateKeyPath || !botId) {
|
|
476
503
|
throw new Error(
|
|
477
|
-
"Missing required fields. Use flags or run interactively."
|
|
504
|
+
"Missing required fields. Use flags, environment variables, or run interactively."
|
|
478
505
|
);
|
|
479
506
|
}
|
|
480
507
|
if (!existsSync2(privateKeyPath)) {
|
|
@@ -527,9 +554,9 @@ var whoamiCommand = new Command3("whoami").description("Show current authenticat
|
|
|
527
554
|
output(
|
|
528
555
|
{
|
|
529
556
|
profile,
|
|
530
|
-
serviceAccount: creds.serviceAccount,
|
|
557
|
+
serviceAccount: creds.serviceAccount ?? "(not set)",
|
|
531
558
|
clientId: creds.clientId,
|
|
532
|
-
botId: creds.botId,
|
|
559
|
+
botId: creds.botId ?? "(not set)",
|
|
533
560
|
domainId: creds.domainId ?? "(not set)",
|
|
534
561
|
tokenValid: isValid,
|
|
535
562
|
tokenExpiresAt
|
|
@@ -624,6 +651,11 @@ function buildContent(opts) {
|
|
|
624
651
|
async function send(opts) {
|
|
625
652
|
const profile = opts.profile ?? "default";
|
|
626
653
|
const creds = await loadCredentials(profile);
|
|
654
|
+
if (!creds.botId) {
|
|
655
|
+
throw new Error(
|
|
656
|
+
"Bot ID is required for sending messages.\nRun `nworks login` with --bot-id flag to set up bot credentials."
|
|
657
|
+
);
|
|
658
|
+
}
|
|
627
659
|
const content = buildContent(opts);
|
|
628
660
|
const body = { content };
|
|
629
661
|
if (opts.to) {
|
|
@@ -648,6 +680,11 @@ async function send(opts) {
|
|
|
648
680
|
}
|
|
649
681
|
async function listMembers(channelId, profile = "default") {
|
|
650
682
|
const creds = await loadCredentials(profile);
|
|
683
|
+
if (!creds.botId) {
|
|
684
|
+
throw new Error(
|
|
685
|
+
"Bot ID is required for listing channel members.\nRun `nworks login` with --bot-id flag to set up bot credentials."
|
|
686
|
+
);
|
|
687
|
+
}
|
|
651
688
|
const result = await request({
|
|
652
689
|
method: "GET",
|
|
653
690
|
path: `/bots/${creds.botId}/channels/${channelId}/members`,
|
|
@@ -855,7 +892,9 @@ async function getEvent(eventId, userId = "me", profile = "default") {
|
|
|
855
892
|
const res = await authedFetch(url2, { method: "GET" }, profile);
|
|
856
893
|
if (!res.ok) return handleError(res);
|
|
857
894
|
const data = await res.json();
|
|
858
|
-
|
|
895
|
+
const event = data.eventComponents[0];
|
|
896
|
+
if (!event) throw new ApiError("NOT_FOUND", "Event not found", 404);
|
|
897
|
+
return event;
|
|
859
898
|
}
|
|
860
899
|
async function updateEvent(opts) {
|
|
861
900
|
const userId = opts.userId ?? "me";
|
|
@@ -1756,9 +1795,223 @@ var deleteCommand2 = new Command9("delete").description("Delete a task (requires
|
|
|
1756
1795
|
});
|
|
1757
1796
|
var taskCommand = new Command9("task").description("Task operations (requires User OAuth with task scope)").addCommand(listCommand4).addCommand(createCommand2).addCommand(updateCommand2).addCommand(deleteCommand2);
|
|
1758
1797
|
|
|
1759
|
-
// src/commands/
|
|
1798
|
+
// src/commands/board.ts
|
|
1760
1799
|
import { Command as Command10 } from "commander";
|
|
1761
1800
|
|
|
1801
|
+
// src/api/board.ts
|
|
1802
|
+
var BASE_URL6 = "https://www.worksapis.com/v1.0";
|
|
1803
|
+
async function authedFetch5(url2, init, profile) {
|
|
1804
|
+
const token = await getValidUserToken(profile);
|
|
1805
|
+
const headers = new Headers(init.headers);
|
|
1806
|
+
headers.set("Authorization", `Bearer ${token}`);
|
|
1807
|
+
return fetch(url2, { ...init, headers });
|
|
1808
|
+
}
|
|
1809
|
+
async function handleError5(res) {
|
|
1810
|
+
if (res.status === 401) {
|
|
1811
|
+
throw new AuthError("User token expired. Run `nworks login --user --scope board` again.");
|
|
1812
|
+
}
|
|
1813
|
+
let code = "UNKNOWN";
|
|
1814
|
+
let description = `HTTP ${res.status}`;
|
|
1815
|
+
try {
|
|
1816
|
+
const body = await res.json();
|
|
1817
|
+
code = body.code ?? code;
|
|
1818
|
+
description = body.description ?? description;
|
|
1819
|
+
} catch {
|
|
1820
|
+
}
|
|
1821
|
+
throw new ApiError(code, description, res.status);
|
|
1822
|
+
}
|
|
1823
|
+
function safeParseJson(text) {
|
|
1824
|
+
const safe = text.replace(
|
|
1825
|
+
/"((?:board|post|domain|user)Id)"\s*:\s*(\d{16,})/g,
|
|
1826
|
+
'"$1":"$2"'
|
|
1827
|
+
);
|
|
1828
|
+
return JSON.parse(safe);
|
|
1829
|
+
}
|
|
1830
|
+
async function listBoards(count = 20, cursor, profile = "default") {
|
|
1831
|
+
const params = new URLSearchParams();
|
|
1832
|
+
params.set("count", String(count));
|
|
1833
|
+
if (cursor) params.set("cursor", cursor);
|
|
1834
|
+
const url2 = `${BASE_URL6}/boards?${params.toString()}`;
|
|
1835
|
+
if (process.env["NWORKS_VERBOSE"] === "1") {
|
|
1836
|
+
console.error(`[nworks] GET ${url2}`);
|
|
1837
|
+
}
|
|
1838
|
+
const res = await authedFetch5(url2, { method: "GET" }, profile);
|
|
1839
|
+
if (!res.ok) return handleError5(res);
|
|
1840
|
+
const text = await res.text();
|
|
1841
|
+
if (process.env["NWORKS_VERBOSE"] === "1") {
|
|
1842
|
+
console.error(`[nworks] Response: ${text}`);
|
|
1843
|
+
}
|
|
1844
|
+
const data = safeParseJson(text);
|
|
1845
|
+
return { boards: data.boards ?? [], responseMetaData: data.responseMetaData };
|
|
1846
|
+
}
|
|
1847
|
+
async function listPosts(boardId, count = 20, cursor, profile = "default") {
|
|
1848
|
+
const params = new URLSearchParams();
|
|
1849
|
+
params.set("count", String(count));
|
|
1850
|
+
if (cursor) params.set("cursor", cursor);
|
|
1851
|
+
const url2 = `${BASE_URL6}/boards/${boardId}/posts?${params.toString()}`;
|
|
1852
|
+
if (process.env["NWORKS_VERBOSE"] === "1") {
|
|
1853
|
+
console.error(`[nworks] GET ${url2}`);
|
|
1854
|
+
}
|
|
1855
|
+
const res = await authedFetch5(url2, { method: "GET" }, profile);
|
|
1856
|
+
if (!res.ok) return handleError5(res);
|
|
1857
|
+
const text = await res.text();
|
|
1858
|
+
if (process.env["NWORKS_VERBOSE"] === "1") {
|
|
1859
|
+
console.error(`[nworks] Response: ${text}`);
|
|
1860
|
+
}
|
|
1861
|
+
const data = safeParseJson(text);
|
|
1862
|
+
return { posts: data.posts ?? [], responseMetaData: data.responseMetaData };
|
|
1863
|
+
}
|
|
1864
|
+
async function readPost(boardId, postId, profile = "default") {
|
|
1865
|
+
const url2 = `${BASE_URL6}/boards/${boardId}/posts/${postId}`;
|
|
1866
|
+
if (process.env["NWORKS_VERBOSE"] === "1") {
|
|
1867
|
+
console.error(`[nworks] GET ${url2}`);
|
|
1868
|
+
}
|
|
1869
|
+
const res = await authedFetch5(url2, { method: "GET" }, profile);
|
|
1870
|
+
if (!res.ok) return handleError5(res);
|
|
1871
|
+
const text = await res.text();
|
|
1872
|
+
if (process.env["NWORKS_VERBOSE"] === "1") {
|
|
1873
|
+
console.error(`[nworks] Response: ${text}`);
|
|
1874
|
+
}
|
|
1875
|
+
return safeParseJson(text);
|
|
1876
|
+
}
|
|
1877
|
+
async function createPost(opts) {
|
|
1878
|
+
const profile = opts.profile ?? "default";
|
|
1879
|
+
const body = {
|
|
1880
|
+
title: opts.title,
|
|
1881
|
+
body: opts.body ?? ""
|
|
1882
|
+
};
|
|
1883
|
+
if (opts.enableComment !== void 0) body.enableComment = opts.enableComment;
|
|
1884
|
+
if (opts.sendNotifications !== void 0) body.sendNotifications = opts.sendNotifications;
|
|
1885
|
+
const url2 = `${BASE_URL6}/boards/${opts.boardId}/posts`;
|
|
1886
|
+
if (process.env["NWORKS_VERBOSE"] === "1") {
|
|
1887
|
+
console.error(`[nworks] POST ${url2}`);
|
|
1888
|
+
console.error(`[nworks] Body: ${JSON.stringify(body, null, 2)}`);
|
|
1889
|
+
}
|
|
1890
|
+
const res = await authedFetch5(
|
|
1891
|
+
url2,
|
|
1892
|
+
{
|
|
1893
|
+
method: "POST",
|
|
1894
|
+
headers: { "Content-Type": "application/json" },
|
|
1895
|
+
body: JSON.stringify(body)
|
|
1896
|
+
},
|
|
1897
|
+
profile
|
|
1898
|
+
);
|
|
1899
|
+
if (res.status === 201 || res.ok) {
|
|
1900
|
+
const text = await res.text();
|
|
1901
|
+
if (process.env["NWORKS_VERBOSE"] === "1") {
|
|
1902
|
+
console.error(`[nworks] Response: ${text}`);
|
|
1903
|
+
}
|
|
1904
|
+
return safeParseJson(text);
|
|
1905
|
+
}
|
|
1906
|
+
return handleError5(res);
|
|
1907
|
+
}
|
|
1908
|
+
|
|
1909
|
+
// src/commands/board.ts
|
|
1910
|
+
var listCommand5 = new Command10("list").description("List boards (requires User OAuth with board or board.read scope)").option("--count <n>", "Items per page (default: 20)", "20").option("--cursor <cursor>", "Pagination cursor").option("--profile <name>", "Profile name", "default").option("--json", "JSON output").action(async (opts) => {
|
|
1911
|
+
try {
|
|
1912
|
+
const result = await listBoards(
|
|
1913
|
+
parseInt(opts.count, 10),
|
|
1914
|
+
opts.cursor,
|
|
1915
|
+
opts.profile
|
|
1916
|
+
);
|
|
1917
|
+
const boards = result.boards.map((b) => ({
|
|
1918
|
+
boardId: b.boardId,
|
|
1919
|
+
boardName: b.boardName,
|
|
1920
|
+
description: b.description ?? ""
|
|
1921
|
+
}));
|
|
1922
|
+
output(
|
|
1923
|
+
{ boards, count: boards.length, nextCursor: result.responseMetaData?.nextCursor ?? null },
|
|
1924
|
+
opts
|
|
1925
|
+
);
|
|
1926
|
+
} catch (err) {
|
|
1927
|
+
const error48 = err;
|
|
1928
|
+
errorOutput({ code: error48.code, message: error48.message }, opts);
|
|
1929
|
+
process.exitCode = 1;
|
|
1930
|
+
}
|
|
1931
|
+
});
|
|
1932
|
+
var postsCommand = new Command10("posts").description("List posts in a board (requires User OAuth with board or board.read scope)").requiredOption("--board <boardId>", "Board ID").option("--count <n>", "Items per page (default: 20)", "20").option("--cursor <cursor>", "Pagination cursor").option("--profile <name>", "Profile name", "default").option("--json", "JSON output").action(async (opts) => {
|
|
1933
|
+
try {
|
|
1934
|
+
const result = await listPosts(
|
|
1935
|
+
opts.board,
|
|
1936
|
+
parseInt(opts.count, 10),
|
|
1937
|
+
opts.cursor,
|
|
1938
|
+
opts.profile
|
|
1939
|
+
);
|
|
1940
|
+
const posts = result.posts.map((p) => ({
|
|
1941
|
+
postId: p.postId,
|
|
1942
|
+
title: p.title,
|
|
1943
|
+
userName: p.userName ?? "",
|
|
1944
|
+
readCount: p.readCount ?? 0,
|
|
1945
|
+
commentCount: p.commentCount ?? 0,
|
|
1946
|
+
createdTime: p.createdTime ?? ""
|
|
1947
|
+
}));
|
|
1948
|
+
output(
|
|
1949
|
+
{ posts, count: posts.length, nextCursor: result.responseMetaData?.nextCursor ?? null },
|
|
1950
|
+
opts
|
|
1951
|
+
);
|
|
1952
|
+
} catch (err) {
|
|
1953
|
+
const error48 = err;
|
|
1954
|
+
errorOutput({ code: error48.code, message: error48.message }, opts);
|
|
1955
|
+
process.exitCode = 1;
|
|
1956
|
+
}
|
|
1957
|
+
});
|
|
1958
|
+
var readCommand2 = new Command10("read").description("Read a post detail (requires User OAuth with board or board.read scope)").requiredOption("--board <boardId>", "Board ID").requiredOption("--post <postId>", "Post ID").option("--profile <name>", "Profile name", "default").option("--json", "JSON output").action(async (opts) => {
|
|
1959
|
+
try {
|
|
1960
|
+
const post = await readPost(
|
|
1961
|
+
opts.board,
|
|
1962
|
+
opts.post,
|
|
1963
|
+
opts.profile
|
|
1964
|
+
);
|
|
1965
|
+
output(
|
|
1966
|
+
{
|
|
1967
|
+
postId: post.postId,
|
|
1968
|
+
boardId: post.boardId,
|
|
1969
|
+
title: post.title,
|
|
1970
|
+
body: post.body ?? "",
|
|
1971
|
+
userName: post.userName ?? "",
|
|
1972
|
+
readCount: post.readCount ?? 0,
|
|
1973
|
+
commentCount: post.commentCount ?? 0,
|
|
1974
|
+
createdTime: post.createdTime ?? "",
|
|
1975
|
+
updatedTime: post.updatedTime ?? ""
|
|
1976
|
+
},
|
|
1977
|
+
opts
|
|
1978
|
+
);
|
|
1979
|
+
} catch (err) {
|
|
1980
|
+
const error48 = err;
|
|
1981
|
+
errorOutput({ code: error48.code, message: error48.message }, opts);
|
|
1982
|
+
process.exitCode = 1;
|
|
1983
|
+
}
|
|
1984
|
+
});
|
|
1985
|
+
var createCommand3 = new Command10("create").description("Create a post in a board (requires User OAuth with board scope)").requiredOption("--board <boardId>", "Board ID").requiredOption("--title <title>", "Post title").option("--body <text>", "Post body").option("--no-comment", "Disable comments").option("--notify", "Send notification").option("--profile <name>", "Profile name", "default").option("--json", "JSON output").action(async (opts) => {
|
|
1986
|
+
try {
|
|
1987
|
+
const post = await createPost({
|
|
1988
|
+
boardId: opts.board,
|
|
1989
|
+
title: opts.title,
|
|
1990
|
+
body: opts.body,
|
|
1991
|
+
enableComment: opts.comment,
|
|
1992
|
+
sendNotifications: opts.notify ?? false,
|
|
1993
|
+
profile: opts.profile
|
|
1994
|
+
});
|
|
1995
|
+
output(
|
|
1996
|
+
{
|
|
1997
|
+
success: true,
|
|
1998
|
+
postId: post.postId,
|
|
1999
|
+
boardId: post.boardId,
|
|
2000
|
+
title: post.title
|
|
2001
|
+
},
|
|
2002
|
+
opts
|
|
2003
|
+
);
|
|
2004
|
+
} catch (err) {
|
|
2005
|
+
const error48 = err;
|
|
2006
|
+
errorOutput({ code: error48.code, message: error48.message }, opts);
|
|
2007
|
+
process.exitCode = 1;
|
|
2008
|
+
}
|
|
2009
|
+
});
|
|
2010
|
+
var boardCommand = new Command10("board").description("Board operations (requires User OAuth)").addCommand(listCommand5).addCommand(postsCommand).addCommand(readCommand2).addCommand(createCommand3);
|
|
2011
|
+
|
|
2012
|
+
// src/commands/mcp-cmd.ts
|
|
2013
|
+
import { Command as Command11 } from "commander";
|
|
2014
|
+
|
|
1762
2015
|
// src/mcp/server.ts
|
|
1763
2016
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
1764
2017
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
@@ -16136,6 +16389,127 @@ function registerTools(server) {
|
|
|
16136
16389
|
}
|
|
16137
16390
|
}
|
|
16138
16391
|
);
|
|
16392
|
+
server.tool(
|
|
16393
|
+
"nworks_board_list",
|
|
16394
|
+
"\uAC8C\uC2DC\uD310 \uBAA9\uB85D\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4 (User OAuth board \uB610\uB294 board.read scope \uD544\uC694)",
|
|
16395
|
+
{
|
|
16396
|
+
count: external_exports.number().optional().describe("\uD398\uC774\uC9C0\uB2F9 \uD56D\uBAA9 \uC218 (\uAE30\uBCF8: 20)"),
|
|
16397
|
+
cursor: external_exports.string().optional().describe("\uD398\uC774\uC9C0\uB124\uC774\uC158 \uCEE4\uC11C")
|
|
16398
|
+
},
|
|
16399
|
+
async ({ count, cursor }) => {
|
|
16400
|
+
try {
|
|
16401
|
+
const result = await listBoards(count ?? 20, cursor);
|
|
16402
|
+
const boards = result.boards.map((b) => ({
|
|
16403
|
+
boardId: b.boardId,
|
|
16404
|
+
boardName: b.boardName,
|
|
16405
|
+
description: b.description ?? ""
|
|
16406
|
+
}));
|
|
16407
|
+
return {
|
|
16408
|
+
content: [{ type: "text", text: JSON.stringify({ boards, count: boards.length, nextCursor: result.responseMetaData?.nextCursor ?? null }) }]
|
|
16409
|
+
};
|
|
16410
|
+
} catch (err) {
|
|
16411
|
+
const error48 = err;
|
|
16412
|
+
return {
|
|
16413
|
+
content: [{ type: "text", text: `Error: ${error48.message}` }],
|
|
16414
|
+
isError: true
|
|
16415
|
+
};
|
|
16416
|
+
}
|
|
16417
|
+
}
|
|
16418
|
+
);
|
|
16419
|
+
server.tool(
|
|
16420
|
+
"nworks_board_posts",
|
|
16421
|
+
"\uAC8C\uC2DC\uD310\uC758 \uAE00 \uBAA9\uB85D\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4 (User OAuth board \uB610\uB294 board.read scope \uD544\uC694)",
|
|
16422
|
+
{
|
|
16423
|
+
boardId: external_exports.string().describe("\uAC8C\uC2DC\uD310 ID"),
|
|
16424
|
+
count: external_exports.number().optional().describe("\uD398\uC774\uC9C0\uB2F9 \uD56D\uBAA9 \uC218 (\uAE30\uBCF8: 20, \uCD5C\uB300: 40)"),
|
|
16425
|
+
cursor: external_exports.string().optional().describe("\uD398\uC774\uC9C0\uB124\uC774\uC158 \uCEE4\uC11C")
|
|
16426
|
+
},
|
|
16427
|
+
async ({ boardId, count, cursor }) => {
|
|
16428
|
+
try {
|
|
16429
|
+
const result = await listPosts(boardId, count ?? 20, cursor);
|
|
16430
|
+
const posts = result.posts.map((p) => ({
|
|
16431
|
+
postId: p.postId,
|
|
16432
|
+
title: p.title,
|
|
16433
|
+
userName: p.userName ?? "",
|
|
16434
|
+
readCount: p.readCount ?? 0,
|
|
16435
|
+
commentCount: p.commentCount ?? 0,
|
|
16436
|
+
createdTime: p.createdTime ?? ""
|
|
16437
|
+
}));
|
|
16438
|
+
return {
|
|
16439
|
+
content: [{ type: "text", text: JSON.stringify({ posts, count: posts.length, nextCursor: result.responseMetaData?.nextCursor ?? null }) }]
|
|
16440
|
+
};
|
|
16441
|
+
} catch (err) {
|
|
16442
|
+
const error48 = err;
|
|
16443
|
+
return {
|
|
16444
|
+
content: [{ type: "text", text: `Error: ${error48.message}` }],
|
|
16445
|
+
isError: true
|
|
16446
|
+
};
|
|
16447
|
+
}
|
|
16448
|
+
}
|
|
16449
|
+
);
|
|
16450
|
+
server.tool(
|
|
16451
|
+
"nworks_board_read",
|
|
16452
|
+
"\uAC8C\uC2DC\uD310 \uAE00\uC758 \uC0C1\uC138 \uB0B4\uC6A9\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4 (User OAuth board \uB610\uB294 board.read scope \uD544\uC694)",
|
|
16453
|
+
{
|
|
16454
|
+
boardId: external_exports.string().describe("\uAC8C\uC2DC\uD310 ID"),
|
|
16455
|
+
postId: external_exports.string().describe("\uAE00 ID")
|
|
16456
|
+
},
|
|
16457
|
+
async ({ boardId, postId }) => {
|
|
16458
|
+
try {
|
|
16459
|
+
const post = await readPost(boardId, postId);
|
|
16460
|
+
return {
|
|
16461
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
16462
|
+
postId: post.postId,
|
|
16463
|
+
boardId: post.boardId,
|
|
16464
|
+
title: post.title,
|
|
16465
|
+
body: post.body ?? "",
|
|
16466
|
+
userName: post.userName ?? "",
|
|
16467
|
+
readCount: post.readCount ?? 0,
|
|
16468
|
+
commentCount: post.commentCount ?? 0,
|
|
16469
|
+
createdTime: post.createdTime ?? "",
|
|
16470
|
+
updatedTime: post.updatedTime ?? ""
|
|
16471
|
+
}) }]
|
|
16472
|
+
};
|
|
16473
|
+
} catch (err) {
|
|
16474
|
+
const error48 = err;
|
|
16475
|
+
return {
|
|
16476
|
+
content: [{ type: "text", text: `Error: ${error48.message}` }],
|
|
16477
|
+
isError: true
|
|
16478
|
+
};
|
|
16479
|
+
}
|
|
16480
|
+
}
|
|
16481
|
+
);
|
|
16482
|
+
server.tool(
|
|
16483
|
+
"nworks_board_create",
|
|
16484
|
+
"\uAC8C\uC2DC\uD310\uC5D0 \uAE00\uC744 \uC791\uC131\uD569\uB2C8\uB2E4 (User OAuth board scope \uD544\uC694)",
|
|
16485
|
+
{
|
|
16486
|
+
boardId: external_exports.string().describe("\uAC8C\uC2DC\uD310 ID"),
|
|
16487
|
+
title: external_exports.string().describe("\uAE00 \uC81C\uBAA9"),
|
|
16488
|
+
body: external_exports.string().optional().describe("\uAE00 \uBCF8\uBB38"),
|
|
16489
|
+
enableComment: external_exports.boolean().optional().describe("\uB313\uAE00 \uD5C8\uC6A9 (\uAE30\uBCF8: true)"),
|
|
16490
|
+
sendNotifications: external_exports.boolean().optional().describe("\uC54C\uB9BC \uBC1C\uC1A1 (\uAE30\uBCF8: false)")
|
|
16491
|
+
},
|
|
16492
|
+
async ({ boardId, title, body, enableComment, sendNotifications }) => {
|
|
16493
|
+
try {
|
|
16494
|
+
const post = await createPost({
|
|
16495
|
+
boardId,
|
|
16496
|
+
title,
|
|
16497
|
+
body,
|
|
16498
|
+
enableComment,
|
|
16499
|
+
sendNotifications
|
|
16500
|
+
});
|
|
16501
|
+
return {
|
|
16502
|
+
content: [{ type: "text", text: JSON.stringify({ success: true, postId: post.postId, boardId: post.boardId, title: post.title }) }]
|
|
16503
|
+
};
|
|
16504
|
+
} catch (err) {
|
|
16505
|
+
const error48 = err;
|
|
16506
|
+
return {
|
|
16507
|
+
content: [{ type: "text", text: `Error: ${error48.message}` }],
|
|
16508
|
+
isError: true
|
|
16509
|
+
};
|
|
16510
|
+
}
|
|
16511
|
+
}
|
|
16512
|
+
);
|
|
16139
16513
|
server.tool(
|
|
16140
16514
|
"nworks_whoami",
|
|
16141
16515
|
"\uD604\uC7AC \uC778\uC99D\uB41C NAVER WORKS \uACC4\uC815 \uC815\uBCF4\uB97C \uD655\uC778\uD569\uB2C8\uB2E4",
|
|
@@ -16146,9 +16520,9 @@ function registerTools(server) {
|
|
|
16146
16520
|
const token = await loadToken();
|
|
16147
16521
|
const isValid = token ? token.expiresAt > Date.now() / 1e3 : false;
|
|
16148
16522
|
const info = {
|
|
16149
|
-
serviceAccount: creds.serviceAccount,
|
|
16523
|
+
serviceAccount: creds.serviceAccount ?? null,
|
|
16150
16524
|
clientId: creds.clientId,
|
|
16151
|
-
botId: creds.botId,
|
|
16525
|
+
botId: creds.botId ?? null,
|
|
16152
16526
|
tokenValid: isValid
|
|
16153
16527
|
};
|
|
16154
16528
|
return {
|
|
@@ -16167,9 +16541,25 @@ function registerTools(server) {
|
|
|
16167
16541
|
|
|
16168
16542
|
// src/mcp/server.ts
|
|
16169
16543
|
async function startMcpServer() {
|
|
16544
|
+
try {
|
|
16545
|
+
await loadCredentials();
|
|
16546
|
+
} catch {
|
|
16547
|
+
console.error(
|
|
16548
|
+
"[nworks] Authentication required. Run: nworks login"
|
|
16549
|
+
);
|
|
16550
|
+
}
|
|
16551
|
+
try {
|
|
16552
|
+
const userToken = await loadUserToken();
|
|
16553
|
+
if (!userToken) {
|
|
16554
|
+
console.error(
|
|
16555
|
+
"[nworks] User OAuth not configured. Run: nworks login --user"
|
|
16556
|
+
);
|
|
16557
|
+
}
|
|
16558
|
+
} catch {
|
|
16559
|
+
}
|
|
16170
16560
|
const server = new McpServer({
|
|
16171
16561
|
name: "nworks",
|
|
16172
|
-
version: "0.
|
|
16562
|
+
version: "1.0.0"
|
|
16173
16563
|
});
|
|
16174
16564
|
registerTools(server);
|
|
16175
16565
|
const transport = new StdioServerTransport();
|
|
@@ -16177,7 +16567,7 @@ async function startMcpServer() {
|
|
|
16177
16567
|
}
|
|
16178
16568
|
|
|
16179
16569
|
// src/commands/mcp-cmd.ts
|
|
16180
|
-
var mcpCommand = new
|
|
16570
|
+
var mcpCommand = new Command11("mcp").description("Start MCP server (stdio transport)").option("--list-tools", "List available MCP tools").action(async (opts) => {
|
|
16181
16571
|
if (opts.listTools) {
|
|
16182
16572
|
console.log("nworks_message_send \u2014 Send message to user or channel");
|
|
16183
16573
|
console.log("nworks_message_members \u2014 List channel members");
|
|
@@ -16192,7 +16582,7 @@ var mcpCommand = new Command10("mcp").description("Start MCP server (stdio trans
|
|
|
16192
16582
|
// src/index.ts
|
|
16193
16583
|
var require2 = createRequire(import.meta.url);
|
|
16194
16584
|
var { version: version2 } = require2("../package.json");
|
|
16195
|
-
var program = new
|
|
16585
|
+
var program = new Command12().name("nworks").description("NAVER WORKS CLI \u2014 built for humans and AI agents").version(version2).option("--json", "Always output JSON").option("-v, --verbose", "Debug logging").option("--dry-run", "Print request without calling API").option("-p, --profile <name>", "Profile name", "default");
|
|
16196
16586
|
program.addCommand(loginCommand);
|
|
16197
16587
|
program.addCommand(logoutCommand);
|
|
16198
16588
|
program.addCommand(whoamiCommand);
|
|
@@ -16202,6 +16592,7 @@ program.addCommand(calendarCommand);
|
|
|
16202
16592
|
program.addCommand(driveCommand);
|
|
16203
16593
|
program.addCommand(mailCommand);
|
|
16204
16594
|
program.addCommand(taskCommand);
|
|
16595
|
+
program.addCommand(boardCommand);
|
|
16205
16596
|
program.addCommand(mcpCommand);
|
|
16206
16597
|
program.parse();
|
|
16207
16598
|
//# sourceMappingURL=index.js.map
|