@chnxthr/knowledge-mcp 0.0.0-stage → 0.3.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/LICENSE +21 -0
- package/README.md +37 -2
- package/dist/bootstrap.d.ts +1 -0
- package/dist/bootstrap.js +18 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +5 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/auth.d.ts +38 -0
- package/dist/core/auth.js +93 -0
- package/dist/core/auth.js.map +1 -0
- package/dist/core/config.d.ts +259 -0
- package/dist/core/config.js +172 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/context.d.ts +25 -0
- package/dist/core/context.js +37 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/env.d.ts +2 -0
- package/dist/core/env.js +5 -0
- package/dist/core/env.js.map +1 -0
- package/dist/core/log_mask.d.ts +10 -0
- package/dist/core/log_mask.js +88 -0
- package/dist/core/log_mask.js.map +1 -0
- package/dist/core/oauth.d.ts +46 -0
- package/dist/core/oauth.js +507 -0
- package/dist/core/oauth.js.map +1 -0
- package/dist/core/paths.d.ts +5 -0
- package/dist/core/paths.js +47 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/scope.d.ts +28 -0
- package/dist/core/scope.js +54 -0
- package/dist/core/scope.js.map +1 -0
- package/dist/core/upstream.d.ts +30 -0
- package/dist/core/upstream.js +164 -0
- package/dist/core/upstream.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin/define.d.ts +144 -0
- package/dist/plugin/define.js +44 -0
- package/dist/plugin/define.js.map +1 -0
- package/dist/plugin/load.d.ts +2 -0
- package/dist/plugin/load.js +41 -0
- package/dist/plugin/load.js.map +1 -0
- package/dist/plugin/ping.d.ts +9 -0
- package/dist/plugin/ping.js +29 -0
- package/dist/plugin/ping.js.map +1 -0
- package/dist/plugin/registry.d.ts +62 -0
- package/dist/plugin/registry.js +248 -0
- package/dist/plugin/registry.js.map +1 -0
- package/dist/plugin/result.d.ts +20 -0
- package/dist/plugin/result.js +59 -0
- package/dist/plugin/result.js.map +1 -0
- package/dist/plugins/drive/chunker.d.ts +28 -0
- package/dist/plugins/drive/chunker.js +356 -0
- package/dist/plugins/drive/chunker.js.map +1 -0
- package/dist/plugins/drive/clean_text.d.ts +13 -0
- package/dist/plugins/drive/clean_text.js +31 -0
- package/dist/plugins/drive/clean_text.js.map +1 -0
- package/dist/plugins/drive/client.d.ts +94 -0
- package/dist/plugins/drive/client.js +220 -0
- package/dist/plugins/drive/client.js.map +1 -0
- package/dist/plugins/drive/embeddings.d.ts +15 -0
- package/dist/plugins/drive/embeddings.js +118 -0
- package/dist/plugins/drive/embeddings.js.map +1 -0
- package/dist/plugins/drive/exclude.d.ts +11 -0
- package/dist/plugins/drive/exclude.js +36 -0
- package/dist/plugins/drive/exclude.js.map +1 -0
- package/dist/plugins/drive/extract_text.d.ts +26 -0
- package/dist/plugins/drive/extract_text.js +95 -0
- package/dist/plugins/drive/extract_text.js.map +1 -0
- package/dist/plugins/drive/get_token.d.ts +5 -0
- package/dist/plugins/drive/get_token.js +128 -0
- package/dist/plugins/drive/get_token.js.map +1 -0
- package/dist/plugins/drive/index.d.ts +5 -0
- package/dist/plugins/drive/index.js +72 -0
- package/dist/plugins/drive/index.js.map +1 -0
- package/dist/plugins/drive/indexer.d.ts +69 -0
- package/dist/plugins/drive/indexer.js +204 -0
- package/dist/plugins/drive/indexer.js.map +1 -0
- package/dist/plugins/drive/mathpix.d.ts +4 -0
- package/dist/plugins/drive/mathpix.js +102 -0
- package/dist/plugins/drive/mathpix.js.map +1 -0
- package/dist/plugins/drive/ooxml.d.ts +17 -0
- package/dist/plugins/drive/ooxml.js +152 -0
- package/dist/plugins/drive/ooxml.js.map +1 -0
- package/dist/plugins/drive/path.d.ts +40 -0
- package/dist/plugins/drive/path.js +87 -0
- package/dist/plugins/drive/path.js.map +1 -0
- package/dist/plugins/drive/qdrant.d.ts +123 -0
- package/dist/plugins/drive/qdrant.js +148 -0
- package/dist/plugins/drive/qdrant.js.map +1 -0
- package/dist/plugins/drive/reindex.d.ts +2 -0
- package/dist/plugins/drive/reindex.js +263 -0
- package/dist/plugins/drive/reindex.js.map +1 -0
- package/dist/plugins/drive/settings.d.ts +11 -0
- package/dist/plugins/drive/settings.js +13 -0
- package/dist/plugins/drive/settings.js.map +1 -0
- package/dist/plugins/drive/sync.d.ts +16 -0
- package/dist/plugins/drive/sync.js +139 -0
- package/dist/plugins/drive/sync.js.map +1 -0
- package/dist/plugins/drive/sync_state.d.ts +3 -0
- package/dist/plugins/drive/sync_state.js +26 -0
- package/dist/plugins/drive/sync_state.js.map +1 -0
- package/dist/plugins/drive/tools/list_drive_folder.d.ts +104 -0
- package/dist/plugins/drive/tools/list_drive_folder.js +221 -0
- package/dist/plugins/drive/tools/list_drive_folder.js.map +1 -0
- package/dist/plugins/drive/tools/read_drive_file.d.ts +66 -0
- package/dist/plugins/drive/tools/read_drive_file.js +206 -0
- package/dist/plugins/drive/tools/read_drive_file.js.map +1 -0
- package/dist/plugins/drive/tools/search_drive.d.ts +52 -0
- package/dist/plugins/drive/tools/search_drive.js +78 -0
- package/dist/plugins/drive/tools/search_drive.js.map +1 -0
- package/dist/plugins/drive/tools/semantic_search_drive.d.ts +109 -0
- package/dist/plugins/drive/tools/semantic_search_drive.js +228 -0
- package/dist/plugins/drive/tools/semantic_search_drive.js.map +1 -0
- package/dist/plugins/github/index.d.ts +1 -0
- package/dist/plugins/github/index.js +27 -0
- package/dist/plugins/github/index.js.map +1 -0
- package/dist/plugins/github/repo_tree.d.ts +57 -0
- package/dist/plugins/github/repo_tree.js +123 -0
- package/dist/plugins/github/repo_tree.js.map +1 -0
- package/dist/plugins/index.d.ts +11 -0
- package/dist/plugins/index.js +7 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/railway/index.d.ts +1 -0
- package/dist/plugins/railway/index.js +21 -0
- package/dist/plugins/railway/index.js.map +1 -0
- package/dist/plugins/railway/tools.d.ts +114 -0
- package/dist/plugins/railway/tools.js +165 -0
- package/dist/plugins/railway/tools.js.map +1 -0
- package/dist/plugins/slack/api.d.ts +63 -0
- package/dist/plugins/slack/api.js +280 -0
- package/dist/plugins/slack/api.js.map +1 -0
- package/dist/plugins/slack/index.d.ts +1 -0
- package/dist/plugins/slack/index.js +80 -0
- package/dist/plugins/slack/index.js.map +1 -0
- package/dist/plugins/slack/tools/slack_files.d.ts +87 -0
- package/dist/plugins/slack/tools/slack_files.js +204 -0
- package/dist/plugins/slack/tools/slack_files.js.map +1 -0
- package/dist/plugins/slack/tools/slack_list_channels.d.ts +46 -0
- package/dist/plugins/slack/tools/slack_list_channels.js +197 -0
- package/dist/plugins/slack/tools/slack_list_channels.js.map +1 -0
- package/dist/plugins/slack/tools/slack_read_channel.d.ts +56 -0
- package/dist/plugins/slack/tools/slack_read_channel.js +150 -0
- package/dist/plugins/slack/tools/slack_read_channel.js.map +1 -0
- package/dist/plugins/slack/tools/slack_search.d.ts +53 -0
- package/dist/plugins/slack/tools/slack_search.js +132 -0
- package/dist/plugins/slack/tools/slack_search.js.map +1 -0
- package/dist/run.d.ts +8 -0
- package/dist/run.js +270 -0
- package/dist/run.js.map +1 -0
- package/dist/server/http.d.ts +5 -0
- package/dist/server/http.js +406 -0
- package/dist/server/http.js.map +1 -0
- package/dist/server/identity.d.ts +17 -0
- package/dist/server/identity.js +47 -0
- package/dist/server/identity.js.map +1 -0
- package/dist/server/mcp.d.ts +7 -0
- package/dist/server/mcp.js +55 -0
- package/dist/server/mcp.js.map +1 -0
- package/dist/server/stdio.d.ts +2 -0
- package/dist/server/stdio.js +40 -0
- package/dist/server/stdio.js.map +1 -0
- package/dist/store/index.d.ts +11 -0
- package/dist/store/index.js +31 -0
- package/dist/store/index.js.map +1 -0
- package/dist/store/keys.d.ts +9 -0
- package/dist/store/keys.js +32 -0
- package/dist/store/keys.js.map +1 -0
- package/dist/store/sqlite.d.ts +38 -0
- package/dist/store/sqlite.js +316 -0
- package/dist/store/sqlite.js.map +1 -0
- package/dist/store/supabase.d.ts +35 -0
- package/dist/store/supabase.js +269 -0
- package/dist/store/supabase.js.map +1 -0
- package/dist/store/supabase_client.d.ts +10 -0
- package/dist/store/supabase_client.js +31 -0
- package/dist/store/supabase_client.js.map +1 -0
- package/dist/store/tool_log.d.ts +12 -0
- package/dist/store/tool_log.js +8 -0
- package/dist/store/tool_log.js.map +1 -0
- package/dist/store/types.d.ts +96 -0
- package/dist/store/types.js +2 -0
- package/dist/store/types.js.map +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +11 -0
- package/dist/version.js.map +1 -0
- package/package.json +80 -4
- package/sql/supabase.sql +185 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/plugins/railway/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE1F,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;AAE/E,MAAM,CAAC,MAAM,aAAa,GAAG,YAAY,CAAC;IACxC,EAAE,EAAE,SAAS;IACb,WAAW,EAAE,wCAAwC;IACrD,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,mBAAmB;IACvD,KAAK,EAAE,CAAC,mBAAmB,EAAE,sBAAsB,EAAE,eAAe,CAAC;IACrE,SAAS,EAAE,GAAG,EAAE,CACd,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB;QAC1D,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,CAAC;QACnH,CAAC,CAAC,EAAE;IACR,YAAY,EAAE,iEAAiE;CAChF,CAAC,CAAC"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Railway 자체 GraphQL 툴 — backboard.railway.app/graphql/v2 직접 호출.
|
|
3
|
+
*
|
|
4
|
+
* 왜 자체 툴: Railway remote MCP(mcp.railway.com)는 OAuth 전용(Project token 거부)이라
|
|
5
|
+
* 무인 서버에서 못 씀. Public GraphQL API 는 token 인증을 지원하므로 이걸 직접 호출.
|
|
6
|
+
*
|
|
7
|
+
* RAILWAY_TOKEN: 전체 프로젝트 조회는 team/account token 필요.
|
|
8
|
+
* project token 은 me/projects 가 막혀 한 프로젝트(project(id))만 가능.
|
|
9
|
+
*
|
|
10
|
+
* 3 툴: railway_services(목록) → railway_deployments(배포상태) → railway_logs(로그)
|
|
11
|
+
*/
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
export declare const railwayServicesTool: import("../../plugin/define.js").Tool<import("@modelcontextprotocol/sdk/server/zod-compat").AnySchema>;
|
|
14
|
+
export declare function handleRailwayServices(): Promise<{
|
|
15
|
+
content: {
|
|
16
|
+
type: "text";
|
|
17
|
+
text: string;
|
|
18
|
+
}[];
|
|
19
|
+
isError: boolean;
|
|
20
|
+
} | {
|
|
21
|
+
content: {
|
|
22
|
+
type: "text";
|
|
23
|
+
text: string;
|
|
24
|
+
}[];
|
|
25
|
+
}>;
|
|
26
|
+
declare const depSchema: z.ZodObject<{
|
|
27
|
+
projectId: z.ZodString;
|
|
28
|
+
serviceId: z.ZodString;
|
|
29
|
+
environmentId: z.ZodString;
|
|
30
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
31
|
+
}, "strip", z.ZodTypeAny, {
|
|
32
|
+
limit: number;
|
|
33
|
+
projectId: string;
|
|
34
|
+
serviceId: string;
|
|
35
|
+
environmentId: string;
|
|
36
|
+
}, {
|
|
37
|
+
projectId: string;
|
|
38
|
+
serviceId: string;
|
|
39
|
+
environmentId: string;
|
|
40
|
+
limit?: number | undefined;
|
|
41
|
+
}>;
|
|
42
|
+
export declare const railwayDeploymentsTool: import("../../plugin/define.js").Tool<z.ZodObject<{
|
|
43
|
+
projectId: z.ZodString;
|
|
44
|
+
serviceId: z.ZodString;
|
|
45
|
+
environmentId: z.ZodString;
|
|
46
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
47
|
+
}, "strip", z.ZodTypeAny, {
|
|
48
|
+
limit: number;
|
|
49
|
+
projectId: string;
|
|
50
|
+
serviceId: string;
|
|
51
|
+
environmentId: string;
|
|
52
|
+
}, {
|
|
53
|
+
projectId: string;
|
|
54
|
+
serviceId: string;
|
|
55
|
+
environmentId: string;
|
|
56
|
+
limit?: number | undefined;
|
|
57
|
+
}>>;
|
|
58
|
+
export declare function handleRailwayDeployments(args: z.infer<typeof depSchema>): Promise<{
|
|
59
|
+
content: {
|
|
60
|
+
type: "text";
|
|
61
|
+
text: string;
|
|
62
|
+
}[];
|
|
63
|
+
isError: boolean;
|
|
64
|
+
} | {
|
|
65
|
+
content: {
|
|
66
|
+
type: "text";
|
|
67
|
+
text: string;
|
|
68
|
+
}[];
|
|
69
|
+
}>;
|
|
70
|
+
declare const logSchema: z.ZodObject<{
|
|
71
|
+
deploymentId: z.ZodString;
|
|
72
|
+
type: z.ZodDefault<z.ZodEnum<["deploy", "build"]>>;
|
|
73
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
74
|
+
filter: z.ZodOptional<z.ZodString>;
|
|
75
|
+
}, "strip", z.ZodTypeAny, {
|
|
76
|
+
type: "build" | "deploy";
|
|
77
|
+
limit: number;
|
|
78
|
+
deploymentId: string;
|
|
79
|
+
filter?: string | undefined;
|
|
80
|
+
}, {
|
|
81
|
+
deploymentId: string;
|
|
82
|
+
filter?: string | undefined;
|
|
83
|
+
type?: "build" | "deploy" | undefined;
|
|
84
|
+
limit?: number | undefined;
|
|
85
|
+
}>;
|
|
86
|
+
export declare const railwayLogsTool: import("../../plugin/define.js").Tool<z.ZodObject<{
|
|
87
|
+
deploymentId: z.ZodString;
|
|
88
|
+
type: z.ZodDefault<z.ZodEnum<["deploy", "build"]>>;
|
|
89
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
90
|
+
filter: z.ZodOptional<z.ZodString>;
|
|
91
|
+
}, "strip", z.ZodTypeAny, {
|
|
92
|
+
type: "build" | "deploy";
|
|
93
|
+
limit: number;
|
|
94
|
+
deploymentId: string;
|
|
95
|
+
filter?: string | undefined;
|
|
96
|
+
}, {
|
|
97
|
+
deploymentId: string;
|
|
98
|
+
filter?: string | undefined;
|
|
99
|
+
type?: "build" | "deploy" | undefined;
|
|
100
|
+
limit?: number | undefined;
|
|
101
|
+
}>>;
|
|
102
|
+
export declare function handleRailwayLogs(args: z.infer<typeof logSchema>): Promise<{
|
|
103
|
+
content: {
|
|
104
|
+
type: "text";
|
|
105
|
+
text: string;
|
|
106
|
+
}[];
|
|
107
|
+
isError: boolean;
|
|
108
|
+
} | {
|
|
109
|
+
content: {
|
|
110
|
+
type: "text";
|
|
111
|
+
text: string;
|
|
112
|
+
}[];
|
|
113
|
+
}>;
|
|
114
|
+
export {};
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Railway 자체 GraphQL 툴 — backboard.railway.app/graphql/v2 직접 호출.
|
|
3
|
+
*
|
|
4
|
+
* 왜 자체 툴: Railway remote MCP(mcp.railway.com)는 OAuth 전용(Project token 거부)이라
|
|
5
|
+
* 무인 서버에서 못 씀. Public GraphQL API 는 token 인증을 지원하므로 이걸 직접 호출.
|
|
6
|
+
*
|
|
7
|
+
* RAILWAY_TOKEN: 전체 프로젝트 조회는 team/account token 필요.
|
|
8
|
+
* project token 은 me/projects 가 막혀 한 프로젝트(project(id))만 가능.
|
|
9
|
+
*
|
|
10
|
+
* 3 툴: railway_services(목록) → railway_deployments(배포상태) → railway_logs(로그)
|
|
11
|
+
*/
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
import { defineTool } from '../../plugin/define.js';
|
|
14
|
+
import { getAuth } from '../../core/context.js';
|
|
15
|
+
import { maskString } from '../../core/log_mask.js';
|
|
16
|
+
const RAILWAY_API = 'https://backboard.railway.app/graphql/v2';
|
|
17
|
+
function railwayHeaders() {
|
|
18
|
+
const token = process.env.RAILWAY_TOKEN || process.env.RAILWAY_MCP_TOKEN;
|
|
19
|
+
if (!token)
|
|
20
|
+
throw new Error('[railway] RAILWAY_TOKEN (또는 RAILWAY_MCP_TOKEN) 미설정');
|
|
21
|
+
return { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' };
|
|
22
|
+
}
|
|
23
|
+
const RAILWAY_TIMEOUT_MS = 20_000;
|
|
24
|
+
async function gql(query, variables) {
|
|
25
|
+
const ctrl = new AbortController();
|
|
26
|
+
const timer = setTimeout(() => ctrl.abort(), RAILWAY_TIMEOUT_MS);
|
|
27
|
+
let r;
|
|
28
|
+
try {
|
|
29
|
+
r = await fetch(RAILWAY_API, {
|
|
30
|
+
method: 'POST',
|
|
31
|
+
headers: railwayHeaders(),
|
|
32
|
+
body: JSON.stringify({ query, variables }),
|
|
33
|
+
signal: ctrl.signal,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
if (e instanceof Error && e.name === 'AbortError') {
|
|
38
|
+
throw new Error(`Railway GraphQL timeout ${RAILWAY_TIMEOUT_MS}ms`);
|
|
39
|
+
}
|
|
40
|
+
throw e;
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
clearTimeout(timer);
|
|
44
|
+
}
|
|
45
|
+
const j = (await r.json());
|
|
46
|
+
if (j.errors?.length)
|
|
47
|
+
throw new Error(`Railway GraphQL: ${j.errors.map((e) => e.message).join('; ')}`);
|
|
48
|
+
return j.data;
|
|
49
|
+
}
|
|
50
|
+
function errOut(e) {
|
|
51
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
52
|
+
return { content: [{ type: 'text', text: `[error] ${msg}` }], isError: true };
|
|
53
|
+
}
|
|
54
|
+
// ── 1. railway_services — 전체 프로젝트·서비스·환경 목록 ──
|
|
55
|
+
export const railwayServicesTool = defineTool({
|
|
56
|
+
name: 'railway_services',
|
|
57
|
+
description: 'Railway 전체 프로젝트·서비스·환경 목록. 배포 상태/로그 조회 전 먼저 호출해 ' +
|
|
58
|
+
'projectId / serviceId / environmentId 를 파악하라. (team token 이면 전체, project token 이면 한 프로젝트)',
|
|
59
|
+
annotations: { readOnlyHint: true },
|
|
60
|
+
run: () => handleRailwayServices(),
|
|
61
|
+
});
|
|
62
|
+
export async function handleRailwayServices() {
|
|
63
|
+
getAuth();
|
|
64
|
+
try {
|
|
65
|
+
const d = await gql(`{
|
|
66
|
+
projects(first: 50) {
|
|
67
|
+
edges { node {
|
|
68
|
+
id name
|
|
69
|
+
services { edges { node { id name } } }
|
|
70
|
+
environments { edges { node { id name } } }
|
|
71
|
+
} }
|
|
72
|
+
}
|
|
73
|
+
}`);
|
|
74
|
+
const projects = (d.projects?.edges ?? []).map((e) => ({
|
|
75
|
+
id: e.node.id,
|
|
76
|
+
name: e.node.name,
|
|
77
|
+
services: (e.node.services?.edges ?? []).map((s) => ({ id: s.node.id, name: s.node.name })),
|
|
78
|
+
environments: (e.node.environments?.edges ?? []).map((v) => ({ id: v.node.id, name: v.node.name })),
|
|
79
|
+
}));
|
|
80
|
+
return {
|
|
81
|
+
content: [{ type: 'text', text: JSON.stringify({ count: projects.length, projects }, null, 2) }],
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
catch (e) {
|
|
85
|
+
return errOut(e);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// ── 2. railway_deployments — 서비스 최근 배포 상태 ──
|
|
89
|
+
const depSchema = z.object({
|
|
90
|
+
projectId: z.string().min(1),
|
|
91
|
+
serviceId: z.string().min(1),
|
|
92
|
+
environmentId: z.string().min(1),
|
|
93
|
+
limit: z.number().int().min(1).max(20).default(5).describe('기본 5 (1~20)'),
|
|
94
|
+
});
|
|
95
|
+
export const railwayDeploymentsTool = defineTool({
|
|
96
|
+
name: 'railway_deployments',
|
|
97
|
+
description: 'Railway 특정 서비스의 최근 배포 상태(SUCCESS/FAILED/BUILDING/CRASHED 등). ' +
|
|
98
|
+
'railway_services 로 얻은 projectId·serviceId·environmentId 를 넣는다.',
|
|
99
|
+
input: depSchema,
|
|
100
|
+
annotations: { readOnlyHint: true },
|
|
101
|
+
run: (args) => handleRailwayDeployments(args),
|
|
102
|
+
});
|
|
103
|
+
export async function handleRailwayDeployments(args) {
|
|
104
|
+
getAuth();
|
|
105
|
+
const { projectId, serviceId, environmentId, limit } = args;
|
|
106
|
+
try {
|
|
107
|
+
const d = await gql(`query($p:String!,$s:String!,$e:String!,$n:Int!){
|
|
108
|
+
deployments(first:$n, input:{ projectId:$p, serviceId:$s, environmentId:$e }) {
|
|
109
|
+
edges { node { id status createdAt staticUrl url } }
|
|
110
|
+
}
|
|
111
|
+
}`, { p: projectId, s: serviceId, e: environmentId, n: limit });
|
|
112
|
+
const deps = (d.deployments?.edges ?? []).map((e) => ({
|
|
113
|
+
id: e.node.id,
|
|
114
|
+
status: e.node.status,
|
|
115
|
+
createdAt: e.node.createdAt,
|
|
116
|
+
url: e.node.staticUrl || e.node.url || null,
|
|
117
|
+
}));
|
|
118
|
+
return {
|
|
119
|
+
content: [{ type: 'text', text: JSON.stringify({ count: deps.length, deployments: deps }, null, 2) }],
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
catch (e) {
|
|
123
|
+
return errOut(e);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// ── 3. railway_logs — 배포/빌드 로그 ──
|
|
127
|
+
const logSchema = z.object({
|
|
128
|
+
deploymentId: z.string().min(1),
|
|
129
|
+
type: z.enum(['deploy', 'build']).default('deploy').describe('기본 deploy'),
|
|
130
|
+
limit: z.number().int().min(1).max(500).default(100).describe('기본 100 (1~500)'),
|
|
131
|
+
filter: z.string().optional().describe('로그 필터 문자열 (선택)'),
|
|
132
|
+
});
|
|
133
|
+
export const railwayLogsTool = defineTool({
|
|
134
|
+
name: 'railway_logs',
|
|
135
|
+
description: 'Railway 배포의 로그 (type="deploy" 런타임 로그 / "build" 빌드 로그). ' +
|
|
136
|
+
'railway_deployments 로 얻은 deploymentId 를 넣는다.',
|
|
137
|
+
input: logSchema,
|
|
138
|
+
annotations: { readOnlyHint: true },
|
|
139
|
+
run: (args) => handleRailwayLogs(args),
|
|
140
|
+
});
|
|
141
|
+
export async function handleRailwayLogs(args) {
|
|
142
|
+
getAuth();
|
|
143
|
+
const { deploymentId, type, limit, filter } = args;
|
|
144
|
+
try {
|
|
145
|
+
const field = type === 'build' ? 'buildLogs' : 'deploymentLogs';
|
|
146
|
+
const d = await gql(`query($d:String!,$n:Int!,$f:String){
|
|
147
|
+
${field}(deploymentId:$d, limit:$n, filter:$f) { message timestamp severity }
|
|
148
|
+
}`, { d: deploymentId, n: limit, f: filter });
|
|
149
|
+
const logs = (d[field] ?? []);
|
|
150
|
+
return {
|
|
151
|
+
content: [
|
|
152
|
+
{
|
|
153
|
+
type: 'text',
|
|
154
|
+
text: JSON.stringify(
|
|
155
|
+
// 로그 본문의 토큰·키는 응답 전에 가린다 — 로그를 읽는 사람이 그 서비스의 비밀값까지 보지 않게.
|
|
156
|
+
{ type, count: logs.length, logs: logs.map((l) => ({ ts: l.timestamp, sev: l.severity, msg: maskString(l.message ?? '') })) }, null, 2),
|
|
157
|
+
},
|
|
158
|
+
],
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
catch (e) {
|
|
162
|
+
return errOut(e);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../src/plugins/railway/tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slack Web API wrapper — read-only (대화 읽기 + 파일 다운로드).
|
|
3
|
+
*
|
|
4
|
+
* SDK(@slack/web-api) 없이 fetch 직접 호출 — 의존성 최소화.
|
|
5
|
+
*
|
|
6
|
+
* 토큰 (용도별 분기, 서로 대신 쓰지 않음):
|
|
7
|
+
* - SLACK_USER_TOKEN (xoxp-…) → search.messages / search.files 전용. 결과는 "봇이 멤버인 채널"로 거른다.
|
|
8
|
+
* - SLACK_BOT_TOKEN (xoxb-…) → conversations.* / files.* / users.list (봇이 채널 멤버여야 history 조회 가능).
|
|
9
|
+
* - SLACK_TOKEN → 접두사(xoxp-/xoxb-)로 용도를 판별해, 비어 있는 쪽에만 쓴다.
|
|
10
|
+
* user token 을 bot 자리에 쓰지 않는 이유: "봇이 볼 수 있는 범위"가 토큰 주인의 DM·비공개 채널로 넓어져
|
|
11
|
+
* 모든 MCP 사용자에게 열린다.
|
|
12
|
+
*
|
|
13
|
+
* 필요 OAuth scope (read-only):
|
|
14
|
+
* - User token : search:read
|
|
15
|
+
* - Bot token : channels:history, groups:history, channels:read, groups:read, files:read, users:read
|
|
16
|
+
* (DM 은 읽지 않으므로 im:history, mpim:history 는 필요 없다)
|
|
17
|
+
*/
|
|
18
|
+
export type SlackTokenKind = 'search' | 'bot';
|
|
19
|
+
export declare class SlackError extends Error {
|
|
20
|
+
constructor(message: string);
|
|
21
|
+
}
|
|
22
|
+
/** search.* 용 user token (xoxp). 없으면 undefined. */
|
|
23
|
+
export declare function slackUserToken(): string | undefined;
|
|
24
|
+
/** conversations.* / files.* 용 bot token (xoxb). 없으면 undefined. */
|
|
25
|
+
export declare function slackBotToken(): string | undefined;
|
|
26
|
+
/** 용도에 맞는 토큰 선택. 다른 종류 토큰으로 대신하지 않는다. */
|
|
27
|
+
export declare function getSlackToken(kind: SlackTokenKind): string;
|
|
28
|
+
/**
|
|
29
|
+
* Slack Web API 호출. 응답 `ok=false` 면 SlackError throw.
|
|
30
|
+
* params 는 application/x-www-form-urlencoded 로 전송 (Slack 권장 — 모든 메서드 호환).
|
|
31
|
+
* 429(rate limit)·일시 timeout 은 `Retry-After` 존중해 재시도(기본 2회). search 는 Tier2 라 429 가
|
|
32
|
+
* 잦고 병렬(mapLimit)이 이를 유발하는데, 백오프가 없으면 thread 확장이 조용히 "unavailable" 로
|
|
33
|
+
* 오표기됐다 → 재시도로 신뢰성 확보.
|
|
34
|
+
*/
|
|
35
|
+
export declare function slackApi<T = any>(method: string, params: Record<string, string | number | boolean | undefined>, kind: SlackTokenKind, retries?: number): Promise<T>;
|
|
36
|
+
/** 동시성 제한 병렬 map — Slack rate limit 을 보호하며 순차 N+1 을 제거. */
|
|
37
|
+
export declare function mapLimit<T, R>(items: T[], limit: number, fn: (item: T, index: number) => Promise<R>): Promise<R[]>;
|
|
38
|
+
/** users.list 로 ID→이름 맵 로드 (TTL 캐시). 실패해도 throw 안 함(이름 없으면 ID 그대로). */
|
|
39
|
+
export declare function loadSlackUserMap(): Promise<Record<string, string>>;
|
|
40
|
+
/**
|
|
41
|
+
* 봇이 멤버인 (공개+비공개) 채널 id 집합. DM·그룹DM 은 conversations.list 에 안 잡혀 자연 제외.
|
|
42
|
+
* 실패 시 직전 캐시가 있으면 그대로, 없으면 빈 집합(fail-closed — 못 읽으면 노출 안 함).
|
|
43
|
+
*/
|
|
44
|
+
export declare function loadBotMemberChannelIds(): Promise<Set<string>>;
|
|
45
|
+
/** 봇이 보는 (공개+비공개) 채널의 name→{id,name} 맵 (TTL 캐시). 실패 시 직전 캐시 유지 or 빈 맵. */
|
|
46
|
+
export declare function loadChannelNameMap(): Promise<Map<string, {
|
|
47
|
+
id: string;
|
|
48
|
+
name: string;
|
|
49
|
+
}>>;
|
|
50
|
+
/** 텍스트로 인라인 표시할 mimetype 인지 (그 외는 메타+URL 만). */
|
|
51
|
+
export declare function isTextualMime(mimetype: string | undefined, filetype: string | undefined): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Slack 파일 본문 다운로드. url_private_download 에 Bearer 인증 필요.
|
|
54
|
+
* 텍스트면 string, 바이너리면 byte 길이만 반환 (MCP text 채널 한계).
|
|
55
|
+
*/
|
|
56
|
+
export declare function downloadSlackFile(urlPrivate: string, opts: {
|
|
57
|
+
asText: boolean;
|
|
58
|
+
maxBytes?: number;
|
|
59
|
+
}): Promise<{
|
|
60
|
+
text?: string;
|
|
61
|
+
bytes: number;
|
|
62
|
+
truncated: boolean;
|
|
63
|
+
}>;
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slack Web API wrapper — read-only (대화 읽기 + 파일 다운로드).
|
|
3
|
+
*
|
|
4
|
+
* SDK(@slack/web-api) 없이 fetch 직접 호출 — 의존성 최소화.
|
|
5
|
+
*
|
|
6
|
+
* 토큰 (용도별 분기, 서로 대신 쓰지 않음):
|
|
7
|
+
* - SLACK_USER_TOKEN (xoxp-…) → search.messages / search.files 전용. 결과는 "봇이 멤버인 채널"로 거른다.
|
|
8
|
+
* - SLACK_BOT_TOKEN (xoxb-…) → conversations.* / files.* / users.list (봇이 채널 멤버여야 history 조회 가능).
|
|
9
|
+
* - SLACK_TOKEN → 접두사(xoxp-/xoxb-)로 용도를 판별해, 비어 있는 쪽에만 쓴다.
|
|
10
|
+
* user token 을 bot 자리에 쓰지 않는 이유: "봇이 볼 수 있는 범위"가 토큰 주인의 DM·비공개 채널로 넓어져
|
|
11
|
+
* 모든 MCP 사용자에게 열린다.
|
|
12
|
+
*
|
|
13
|
+
* 필요 OAuth scope (read-only):
|
|
14
|
+
* - User token : search:read
|
|
15
|
+
* - Bot token : channels:history, groups:history, channels:read, groups:read, files:read, users:read
|
|
16
|
+
* (DM 은 읽지 않으므로 im:history, mpim:history 는 필요 없다)
|
|
17
|
+
*/
|
|
18
|
+
const SLACK_API = 'https://slack.com/api';
|
|
19
|
+
export class SlackError extends Error {
|
|
20
|
+
constructor(message) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.name = 'SlackError';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// 토큰 회전(rotation)을 켠 앱의 access token 은 "xoxe." 접두가 붙는다.
|
|
26
|
+
const USER_TOKEN_RE = /^(xoxe\.)?xoxp-/;
|
|
27
|
+
const BOT_TOKEN_RE = /^(xoxe\.)?xoxb-/;
|
|
28
|
+
function pickToken(explicit, re) {
|
|
29
|
+
if (explicit)
|
|
30
|
+
return re.test(explicit) ? explicit : undefined; // 잘못 넣은 토큰 종류는 쓰지 않는다
|
|
31
|
+
const common = process.env.SLACK_TOKEN;
|
|
32
|
+
return common && re.test(common) ? common : undefined;
|
|
33
|
+
}
|
|
34
|
+
/** search.* 용 user token (xoxp). 없으면 undefined. */
|
|
35
|
+
export function slackUserToken() {
|
|
36
|
+
return pickToken(process.env.SLACK_USER_TOKEN, USER_TOKEN_RE);
|
|
37
|
+
}
|
|
38
|
+
/** conversations.* / files.* 용 bot token (xoxb). 없으면 undefined. */
|
|
39
|
+
export function slackBotToken() {
|
|
40
|
+
return pickToken(process.env.SLACK_BOT_TOKEN, BOT_TOKEN_RE);
|
|
41
|
+
}
|
|
42
|
+
/** 용도에 맞는 토큰 선택. 다른 종류 토큰으로 대신하지 않는다. */
|
|
43
|
+
export function getSlackToken(kind) {
|
|
44
|
+
if (kind === 'search') {
|
|
45
|
+
const t = slackUserToken();
|
|
46
|
+
if (!t) {
|
|
47
|
+
throw new SlackError('검색에는 User token 이 필요합니다. SLACK_USER_TOKEN (xoxp-…) 설정.');
|
|
48
|
+
}
|
|
49
|
+
return t;
|
|
50
|
+
}
|
|
51
|
+
const t = slackBotToken();
|
|
52
|
+
if (!t) {
|
|
53
|
+
throw new SlackError('Bot token 이 없습니다. SLACK_BOT_TOKEN (xoxb-…) 설정.');
|
|
54
|
+
}
|
|
55
|
+
return t;
|
|
56
|
+
}
|
|
57
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
58
|
+
/**
|
|
59
|
+
* Slack Web API 호출. 응답 `ok=false` 면 SlackError throw.
|
|
60
|
+
* params 는 application/x-www-form-urlencoded 로 전송 (Slack 권장 — 모든 메서드 호환).
|
|
61
|
+
* 429(rate limit)·일시 timeout 은 `Retry-After` 존중해 재시도(기본 2회). search 는 Tier2 라 429 가
|
|
62
|
+
* 잦고 병렬(mapLimit)이 이를 유발하는데, 백오프가 없으면 thread 확장이 조용히 "unavailable" 로
|
|
63
|
+
* 오표기됐다 → 재시도로 신뢰성 확보.
|
|
64
|
+
*/
|
|
65
|
+
export async function slackApi(method, params, kind, retries = 2) {
|
|
66
|
+
const token = getSlackToken(kind);
|
|
67
|
+
const body = new URLSearchParams();
|
|
68
|
+
for (const [k, v] of Object.entries(params)) {
|
|
69
|
+
if (v !== undefined)
|
|
70
|
+
body.set(k, String(v));
|
|
71
|
+
}
|
|
72
|
+
for (let attempt = 0;; attempt++) {
|
|
73
|
+
const ctrl = new AbortController();
|
|
74
|
+
const timeoutId = setTimeout(() => ctrl.abort(), 15_000);
|
|
75
|
+
try {
|
|
76
|
+
const resp = await fetch(`${SLACK_API}/${method}`, {
|
|
77
|
+
method: 'POST',
|
|
78
|
+
headers: {
|
|
79
|
+
Authorization: `Bearer ${token}`,
|
|
80
|
+
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
|
|
81
|
+
},
|
|
82
|
+
body: body.toString(),
|
|
83
|
+
signal: ctrl.signal,
|
|
84
|
+
});
|
|
85
|
+
clearTimeout(timeoutId); // fetch 완료 — 재시도 대기 중 타이머 오작동 방지
|
|
86
|
+
// 429: Retry-After(초) 만큼 대기 후 재시도 (상한 30s)
|
|
87
|
+
if (resp.status === 429) {
|
|
88
|
+
if (attempt < retries) {
|
|
89
|
+
const ra = Math.min(Number(resp.headers.get('retry-after')) || 1, 30);
|
|
90
|
+
await sleep(ra * 1000);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
throw new SlackError(`${method} 실패: rate limited (429)`);
|
|
94
|
+
}
|
|
95
|
+
const json = (await resp.json());
|
|
96
|
+
if (!json.ok) {
|
|
97
|
+
// 본문 ratelimited(드묾) 도 재시도
|
|
98
|
+
if (json.error === 'ratelimited' && attempt < retries) {
|
|
99
|
+
await sleep(1000 * (attempt + 1));
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
const detail = json.error ?? `HTTP ${resp.status}`;
|
|
103
|
+
const needed = json.needed ? ` (needed scope: ${json.needed})` : '';
|
|
104
|
+
throw new SlackError(`${method} 실패: ${detail}${needed}`);
|
|
105
|
+
}
|
|
106
|
+
return json;
|
|
107
|
+
}
|
|
108
|
+
catch (e) {
|
|
109
|
+
if (e instanceof SlackError)
|
|
110
|
+
throw e;
|
|
111
|
+
if (e instanceof Error && e.name === 'AbortError') {
|
|
112
|
+
// 일시 timeout — 짧게 대기 후 재시도, 소진 시 에러
|
|
113
|
+
if (attempt < retries) {
|
|
114
|
+
await sleep(500);
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
throw new SlackError(`${method} timeout 15s`);
|
|
118
|
+
}
|
|
119
|
+
throw new SlackError(`${method} fetch 실패: ${e instanceof Error ? e.message : String(e)}`);
|
|
120
|
+
}
|
|
121
|
+
finally {
|
|
122
|
+
clearTimeout(timeoutId);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/** 동시성 제한 병렬 map — Slack rate limit 을 보호하며 순차 N+1 을 제거. */
|
|
127
|
+
export async function mapLimit(items, limit, fn) {
|
|
128
|
+
const out = new Array(items.length);
|
|
129
|
+
let i = 0;
|
|
130
|
+
const worker = async () => {
|
|
131
|
+
while (i < items.length) {
|
|
132
|
+
const idx = i++;
|
|
133
|
+
out[idx] = await fn(items[idx], idx);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
await Promise.all(Array.from({ length: Math.min(limit, items.length) || 0 }, worker));
|
|
137
|
+
return out;
|
|
138
|
+
}
|
|
139
|
+
// 사용자 ID → 표시명 캐시 (분 단위로 거의 안 변함) — 여러 도구가 공유.
|
|
140
|
+
let _userMapCache = null;
|
|
141
|
+
const USER_MAP_TTL_MS = Number(process.env.SLACK_USERMAP_TTL_MS ?? 300_000); // 5분
|
|
142
|
+
/** users.list 로 ID→이름 맵 로드 (TTL 캐시). 실패해도 throw 안 함(이름 없으면 ID 그대로). */
|
|
143
|
+
export async function loadSlackUserMap() {
|
|
144
|
+
const now = Date.now();
|
|
145
|
+
if (_userMapCache && _userMapCache.expiresAt > now)
|
|
146
|
+
return _userMapCache.map;
|
|
147
|
+
const map = {};
|
|
148
|
+
try {
|
|
149
|
+
let cursor;
|
|
150
|
+
for (let page = 0; page < 10; page++) {
|
|
151
|
+
const res = await slackApi('users.list', { limit: 200, cursor }, 'bot');
|
|
152
|
+
for (const m of res.members ?? [])
|
|
153
|
+
map[m.id] = m.real_name || m.name || m.id;
|
|
154
|
+
cursor = res.response_metadata?.next_cursor || undefined;
|
|
155
|
+
if (!cursor)
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
/* users:read scope 없으면 ID 그대로 — 치명적 아님 */
|
|
161
|
+
}
|
|
162
|
+
if (Object.keys(map).length > 0)
|
|
163
|
+
_userMapCache = { map, expiresAt: now + USER_MAP_TTL_MS };
|
|
164
|
+
return map;
|
|
165
|
+
}
|
|
166
|
+
// 봇이 멤버인 채널 id 집합 캐시 — 봇 초대/탈퇴는 드물어 TTL 캐시.
|
|
167
|
+
// search 의 신뢰 경계(봇 멤버 = 허가된 채널)와 thread 확장 가능 여부 판정에 공유.
|
|
168
|
+
let _botMemberCache = null;
|
|
169
|
+
const BOT_MEMBER_TTL_MS = Number(process.env.SLACK_BOT_MEMBER_TTL_MS ?? 300_000); // 5분
|
|
170
|
+
/**
|
|
171
|
+
* 봇이 멤버인 (공개+비공개) 채널 id 집합. DM·그룹DM 은 conversations.list 에 안 잡혀 자연 제외.
|
|
172
|
+
* 실패 시 직전 캐시가 있으면 그대로, 없으면 빈 집합(fail-closed — 못 읽으면 노출 안 함).
|
|
173
|
+
*/
|
|
174
|
+
export async function loadBotMemberChannelIds() {
|
|
175
|
+
const now = Date.now();
|
|
176
|
+
if (_botMemberCache && _botMemberCache.expiresAt > now)
|
|
177
|
+
return _botMemberCache.ids;
|
|
178
|
+
const ids = new Set();
|
|
179
|
+
try {
|
|
180
|
+
let cursor;
|
|
181
|
+
for (let page = 0; page < 10; page++) {
|
|
182
|
+
const res = await slackApi('conversations.list', { types: 'public_channel,private_channel', limit: 1000, exclude_archived: true, cursor }, 'bot');
|
|
183
|
+
for (const c of res.channels ?? [])
|
|
184
|
+
if (c.id && c.is_member)
|
|
185
|
+
ids.add(c.id);
|
|
186
|
+
cursor = res.response_metadata?.next_cursor || undefined;
|
|
187
|
+
if (!cursor)
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
// 실패 시 직전 캐시 유지(만료됐어도) — 일시 장애로 검색을 통째 막지 않게. 캐시 없으면 빈 집합.
|
|
193
|
+
if (_botMemberCache)
|
|
194
|
+
return _botMemberCache.ids;
|
|
195
|
+
return ids;
|
|
196
|
+
}
|
|
197
|
+
_botMemberCache = { ids, expiresAt: now + BOT_MEMBER_TTL_MS };
|
|
198
|
+
return ids;
|
|
199
|
+
}
|
|
200
|
+
// 채널 이름 → {id,name} 캐시 — 이름으로 채널 resolve 시 반복 conversations.list 순회 제거.
|
|
201
|
+
// (slack_read_channel 이 매 호출 최대 10페이지 순차 조회하던 지연을 warmup 후 0콜로.)
|
|
202
|
+
let _channelNameCache = null;
|
|
203
|
+
/** 봇이 보는 (공개+비공개) 채널의 name→{id,name} 맵 (TTL 캐시). 실패 시 직전 캐시 유지 or 빈 맵. */
|
|
204
|
+
export async function loadChannelNameMap() {
|
|
205
|
+
const now = Date.now();
|
|
206
|
+
if (_channelNameCache && _channelNameCache.expiresAt > now)
|
|
207
|
+
return _channelNameCache.byName;
|
|
208
|
+
const byName = new Map();
|
|
209
|
+
try {
|
|
210
|
+
let cursor;
|
|
211
|
+
for (let page = 0; page < 15; page++) {
|
|
212
|
+
const res = await slackApi('conversations.list', { types: 'public_channel,private_channel', limit: 1000, exclude_archived: true, cursor }, 'bot');
|
|
213
|
+
for (const c of res.channels ?? [])
|
|
214
|
+
if (c.id && c.name)
|
|
215
|
+
byName.set(c.name, { id: c.id, name: c.name });
|
|
216
|
+
cursor = res.response_metadata?.next_cursor || undefined;
|
|
217
|
+
if (!cursor)
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
if (_channelNameCache)
|
|
223
|
+
return _channelNameCache.byName; // 일시 장애 — 직전 캐시로 버팀
|
|
224
|
+
}
|
|
225
|
+
if (byName.size > 0)
|
|
226
|
+
_channelNameCache = { byName, expiresAt: now + BOT_MEMBER_TTL_MS };
|
|
227
|
+
return byName;
|
|
228
|
+
}
|
|
229
|
+
/** 텍스트로 인라인 표시할 mimetype 인지 (그 외는 메타+URL 만). */
|
|
230
|
+
export function isTextualMime(mimetype, filetype) {
|
|
231
|
+
const m = (mimetype ?? '').toLowerCase();
|
|
232
|
+
if (m.startsWith('text/'))
|
|
233
|
+
return true;
|
|
234
|
+
if (m === 'application/json' || m === 'application/xml')
|
|
235
|
+
return true;
|
|
236
|
+
const textFiletypes = new Set([
|
|
237
|
+
'text', 'markdown', 'md', 'csv', 'tsv', 'json', 'xml', 'yaml', 'yml',
|
|
238
|
+
'javascript', 'typescript', 'python', 'java', 'go', 'rust', 'c', 'cpp',
|
|
239
|
+
'html', 'css', 'sql', 'shell', 'bash', 'log', 'diff', 'patch',
|
|
240
|
+
]);
|
|
241
|
+
return textFiletypes.has((filetype ?? '').toLowerCase());
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Slack 파일 본문 다운로드. url_private_download 에 Bearer 인증 필요.
|
|
245
|
+
* 텍스트면 string, 바이너리면 byte 길이만 반환 (MCP text 채널 한계).
|
|
246
|
+
*/
|
|
247
|
+
export async function downloadSlackFile(urlPrivate, opts) {
|
|
248
|
+
const token = getSlackToken('bot');
|
|
249
|
+
const maxBytes = opts.maxBytes ?? 200_000;
|
|
250
|
+
const ctrl = new AbortController();
|
|
251
|
+
const timeoutId = setTimeout(() => ctrl.abort(), 15_000);
|
|
252
|
+
try {
|
|
253
|
+
const resp = await fetch(urlPrivate, {
|
|
254
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
255
|
+
signal: ctrl.signal,
|
|
256
|
+
});
|
|
257
|
+
if (!resp.ok) {
|
|
258
|
+
throw new SlackError(`파일 다운로드 실패: HTTP ${resp.status}`);
|
|
259
|
+
}
|
|
260
|
+
const buf = Buffer.from(await resp.arrayBuffer());
|
|
261
|
+
const truncated = buf.length > maxBytes;
|
|
262
|
+
if (opts.asText) {
|
|
263
|
+
const slice = truncated ? buf.subarray(0, maxBytes) : buf;
|
|
264
|
+
return { text: slice.toString('utf-8'), bytes: buf.length, truncated };
|
|
265
|
+
}
|
|
266
|
+
return { bytes: buf.length, truncated: false };
|
|
267
|
+
}
|
|
268
|
+
catch (e) {
|
|
269
|
+
if (e instanceof SlackError)
|
|
270
|
+
throw e;
|
|
271
|
+
if (e instanceof Error && e.name === 'AbortError') {
|
|
272
|
+
throw new SlackError('파일 다운로드 timeout 15s');
|
|
273
|
+
}
|
|
274
|
+
throw new SlackError(`파일 다운로드 실패: ${e instanceof Error ? e.message : String(e)}`);
|
|
275
|
+
}
|
|
276
|
+
finally {
|
|
277
|
+
clearTimeout(timeoutId);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/plugins/slack/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const slackPlugin: import("../../plugin/define.js").Plugin;
|