Skip to content

Commit 55a682e

Browse files
authored
Merge pull request #989 from seocylucky/vibe
fix: Smithery 실행 시 import.meta.url 및 i18n 경로 에러 해결
2 parents cd66777 + 3e64f77 commit 55a682e

File tree

5 files changed

+302
-277
lines changed

5 files changed

+302
-277
lines changed

packages/mcp/src/common/i18n.ts

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
1-
import * as fs from 'fs';
2-
import * as path from 'path';
3-
import { fileURLToPath } from 'url';
1+
import * as fs from "fs";
2+
import * as path from "path";
3+
import { getDirname } from "./utils.js";
44

5-
const __filename = fileURLToPath(import.meta.url);
6-
const __dirname = path.dirname(__filename);
5+
const __dirname = getDirname();
6+
7+
function findLocalesDir(): string {
8+
const cands = [
9+
path.resolve(__dirname, "../resources/locales"),
10+
path.resolve(__dirname, "../../resources/locales"),
11+
path.resolve(process.cwd(), "src/resources/locales"),
12+
path.resolve(process.cwd(), "resources/locales"),
13+
];
14+
for (const p of cands) {
15+
if (fs.existsSync(path.join(p, "en.json"))) return p;
16+
}
17+
throw new Error("Cannot locate locales directory. Tried:\n" + cands.map((p) => " - " + p).join("\n"));
18+
}
19+
20+
const LOCALES_DIR = findLocalesDir();
721

822
class I18nManager {
9-
private currentLocale = 'en';
23+
private currentLocale = "en";
1024
private translations: Record<string, any> = {};
1125
private fallbackTranslations: Record<string, any> = {};
1226

@@ -16,28 +30,28 @@ class I18nManager {
1630

1731
private loadFallback() {
1832
try {
19-
const fallbackPath = path.join(__dirname, '../resources/locales/en.json');
20-
const fallbackData = fs.readFileSync(fallbackPath, 'utf-8');
33+
const fallbackPath = path.join(LOCALES_DIR, "en.json");
34+
const fallbackData = fs.readFileSync(fallbackPath, "utf-8");
2135
this.fallbackTranslations = JSON.parse(fallbackData);
2236
this.translations = this.fallbackTranslations;
2337
} catch (error) {
24-
console.error('Failed to load fallback translations:', error);
38+
console.error("Failed to load fallback translations:", error);
2539
this.fallbackTranslations = {};
2640
this.translations = {};
2741
}
2842
}
2943

3044
setLocale(locale: string) {
3145
this.currentLocale = locale;
32-
33-
if (locale === 'en') {
46+
47+
if (locale === "en") {
3448
this.translations = this.fallbackTranslations;
3549
return;
3650
}
3751

3852
try {
39-
const localePath = path.join(__dirname, `../resources/locales/${locale}.json`);
40-
const localeData = fs.readFileSync(localePath, 'utf-8');
53+
const localePath = path.join(LOCALES_DIR, `${locale}.json`);
54+
const localeData = fs.readFileSync(localePath, "utf-8");
4155
this.translations = JSON.parse(localeData);
4256
} catch (error) {
4357
console.error(`Locale '${locale}' not found, using English fallback`);
@@ -46,32 +60,30 @@ class I18nManager {
4660
}
4761

4862
t(key: string, params?: Record<string, any>): string {
49-
const keys = key.split('.');
63+
const keys = key.split(".");
5064
let value: any = this.translations;
51-
65+
5266
for (const k of keys) {
5367
value = value?.[k];
5468
}
55-
56-
if (!value && this.currentLocale !== 'en') {
69+
70+
if (!value && this.currentLocale !== "en") {
5771
value = this.fallbackTranslations;
5872
for (const k of keys) {
5973
value = value?.[k];
6074
}
6175
}
62-
63-
if (!value || typeof value !== 'string') {
76+
77+
if (!value || typeof value !== "string") {
6478
return key;
6579
}
66-
80+
6781
const stringValue = value as string;
68-
82+
6983
if (params) {
70-
return stringValue.replace(/\{(\w+)\}/g, (match: string, param: string) =>
71-
params[param]?.toString() ?? match
72-
);
84+
return stringValue.replace(/\{(\w+)\}/g, (match: string, param: string) => params[param]?.toString() ?? match);
7385
}
74-
86+
7587
return stringValue;
7688
}
7789

packages/mcp/src/common/utils.ts

Lines changed: 51 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,15 @@ import relativeTime from "dayjs/plugin/relativeTime.js";
44
import customParseFormat from "dayjs/plugin/customParseFormat.js";
55
import * as cp from "child_process";
66
import type { GitHubRepoInfo } from "./types.js";
7+
import path from "node:path";
8+
import { fileURLToPath } from "node:url";
79

810
dayjs.extend(relativeTime);
911
dayjs.extend(customParseFormat);
1012

1113
// Git 로그 포맷 (vscode와 동일)
1214
const GIT_LOG_FORMAT =
13-
"%n%n" +
14-
[
15-
"%H",
16-
"%P",
17-
"%D",
18-
"%an",
19-
"%ae",
20-
"%ad",
21-
"%cn",
22-
"%ce",
23-
"%cd",
24-
"%w(0,0,4)%s",
25-
"%b",
26-
].join("%n");
15+
"%n%n" + ["%H", "%P", "%D", "%an", "%ae", "%ad", "%cn", "%ce", "%cd", "%w(0,0,4)%s", "%b"].join("%n");
2716

2817
function resolveSpawnOutput(cmd: cp.ChildProcess) {
2918
return Promise.all([
@@ -62,26 +51,30 @@ export const GitHubUtils = {
6251
.replace(/^https?:\/\/github\.com\//, "")
6352
.replace(/\.git$/, "")
6453
.replace(/\/+$/, "");
65-
54+
6655
const [owner, repo] = cleaned.split("/");
67-
56+
6857
if (!owner || !repo) {
69-
throw new Error(`Invalid repository path: ${repoUrlOrPath}. Expected format: "owner/repo" or "https://github.com/owner/repo"`);
58+
throw new Error(
59+
`Invalid repository path: ${repoUrlOrPath}. Expected format: "owner/repo" or "https://github.com/owner/repo"`
60+
);
7061
}
71-
62+
7263
return { owner, repo };
7364
},
7465

7566
parseTimeRange(since?: string, until?: string): { since: string; until: string } {
7667
const now = dayjs();
7768

78-
let sinceDate = now.subtract(90, 'day');
69+
let sinceDate = now.subtract(90, "day");
7970
if (since) {
8071
const parsedSince = this.parseFlexibleDate(since);
8172
if (parsedSince) {
8273
sinceDate = parsedSince;
8374
} else {
84-
throw new Error(`Invalid date format: ${since}. Try formats like "30 days ago", "2024-01-01", "last month", "yesterday", or "30d"`);
75+
throw new Error(
76+
`Invalid date format: ${since}. Try formats like "30 days ago", "2024-01-01", "last month", "yesterday", or "30d"`
77+
);
8578
}
8679
}
8780

@@ -91,7 +84,9 @@ export const GitHubUtils = {
9184
if (parsedUntil) {
9285
untilDate = parsedUntil;
9386
} else {
94-
throw new Error(`Invalid date format: ${until}. Try formats like "yesterday", "2024-01-01", "last week", or "today"`);
87+
throw new Error(
88+
`Invalid date format: ${until}. Try formats like "yesterday", "2024-01-01", "last week", or "today"`
89+
);
9590
}
9691
}
9792

@@ -106,14 +101,14 @@ export const GitHubUtils = {
106101
const now = dayjs();
107102

108103
const patterns = [
109-
{ regex: /^(\d+)\s*days?\s*ago$/i, unit: 'day' },
110-
{ regex: /^(\d+)\s*weeks?\s*ago$/i, unit: 'week' },
111-
{ regex: /^(\d+)\s*months?\s*ago$/i, unit: 'month' },
112-
{ regex: /^(\d+)\s*years?\s*ago$/i, unit: 'year' },
113-
{ regex: /^(\d+)d$/i, unit: 'day' },
114-
{ regex: /^(\d+)w$/i, unit: 'week' },
115-
{ regex: /^(\d+)m$/i, unit: 'month' },
116-
{ regex: /^(\d+)y$/i, unit: 'year' },
104+
{ regex: /^(\d+)\s*days?\s*ago$/i, unit: "day" },
105+
{ regex: /^(\d+)\s*weeks?\s*ago$/i, unit: "week" },
106+
{ regex: /^(\d+)\s*months?\s*ago$/i, unit: "month" },
107+
{ regex: /^(\d+)\s*years?\s*ago$/i, unit: "year" },
108+
{ regex: /^(\d+)d$/i, unit: "day" },
109+
{ regex: /^(\d+)w$/i, unit: "week" },
110+
{ regex: /^(\d+)m$/i, unit: "month" },
111+
{ regex: /^(\d+)y$/i, unit: "year" },
117112
];
118113

119114
for (const { regex, unit } of patterns) {
@@ -127,11 +122,11 @@ export const GitHubUtils = {
127122
}
128123

129124
const quickFormats = {
130-
'yesterday': () => now.subtract(1, 'day'),
131-
'today': () => now,
132-
'last week': () => now.subtract(1, 'week'),
133-
'last month': () => now.subtract(1, 'month'),
134-
'last year': () => now.subtract(1, 'year'),
125+
yesterday: () => now.subtract(1, "day"),
126+
today: () => now,
127+
"last week": () => now.subtract(1, "week"),
128+
"last month": () => now.subtract(1, "month"),
129+
"last year": () => now.subtract(1, "year"),
135130
};
136131

137132
if (quickFormats[str as keyof typeof quickFormats]) {
@@ -241,7 +236,7 @@ export const GitHubUtils = {
241236

242237
async cloneRepository(githubToken: string, owner: string, repo: string, targetPath: string): Promise<void> {
243238
const repoUrl = `https://${githubToken}@github.com/${owner}/${repo}.git`;
244-
239+
245240
const [status, stdout, stderr] = await resolveSpawnOutput(
246241
cp.spawn("git", ["clone", repoUrl, targetPath], {
247242
env: Object.assign({}, process.env),
@@ -255,14 +250,14 @@ export const GitHubUtils = {
255250

256251
async getDefaultBranch(githubToken: string, owner: string, repo: string): Promise<string> {
257252
const octokit = this.createGitHubAPIClient(githubToken);
258-
253+
259254
try {
260255
const repoInfo = await octokit.repos.get({ owner, repo });
261256
return repoInfo.data.default_branch;
262257
} catch (error: any) {
263258
throw new Error(`Failed to get default branch: ${error.message}`);
264259
}
265-
}
260+
},
266261
};
267262

268263
export const CommonUtils = {
@@ -280,9 +275,26 @@ export const CommonUtils = {
280275
return chunks;
281276
},
282277
safeParseInt(value: string | number): number {
283-
if (typeof value === 'number') return value;
278+
if (typeof value === "number") return value;
284279
const parsed = parseInt(value);
285280
return isNaN(parsed) ? 0 : parsed;
286-
}
281+
},
287282
};
288283

284+
export function getFilename(): string {
285+
if (typeof __filename !== "undefined") return __filename;
286+
try {
287+
const metaUrl = (0, eval)("import.meta.url");
288+
if (metaUrl) return fileURLToPath(metaUrl);
289+
} catch {}
290+
return path.join(process.cwd(), "index.js");
291+
}
292+
293+
export function getDirname(): string {
294+
if (typeof __dirname !== "undefined") return __dirname;
295+
try {
296+
const metaUrl = (0, eval)("import.meta.url");
297+
if (metaUrl) return path.dirname(fileURLToPath(metaUrl));
298+
} catch {}
299+
return process.cwd();
300+
}

packages/mcp/src/core/authorWorkPattern.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
import * as fs from "fs/promises";
22
import * as path from "path";
3-
import { fileURLToPath } from "url";
3+
import { getDirname } from "../common/utils.js";
44
import type { RestEndpointMethodTypes } from "@octokit/rest";
55
import { GitHubUtils } from "../common/utils.js";
66
import { I18n } from "../common/i18n.js";
77
import { Config } from "../common/config.js";
88

9-
const __filename = fileURLToPath(import.meta.url);
10-
const __dirname = path.dirname(__filename);
9+
const __dirname = getDirname();
1110

1211
type CommitListItem = RestEndpointMethodTypes["repos"]["listCommits"]["response"]["data"][number];
1312
type GetCommitResponse = RestEndpointMethodTypes["repos"]["getCommit"]["response"]["data"];

0 commit comments

Comments
 (0)