@bimatrix-aud-platform/aud_mcp_server 1.1.52 → 1.1.56
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/generators/fixer.js +25 -0
- package/dist/index.js +26 -29
- package/dist/resources/encrypted-commands.d.ts +3 -3
- package/dist/resources/encrypted-commands.js +3 -3
- package/dist/utils/mtsd-file-ref.d.ts +30 -0
- package/dist/utils/mtsd-file-ref.js +174 -0
- package/dist/utils/report-publisher.d.ts +1 -9
- package/dist/utils/report-publisher.js +48 -59
- package/package.json +1 -1
- package/schemas/mtsd.interface.ts +4 -4
- package/schemas/mtsd.schema.json +3 -3
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MTSD/SC 파일 경로 참조 유틸리티
|
|
3
|
+
*
|
|
4
|
+
* 로컬 .mtsd/.sc 파일에서 인라인 스크립트/SQL을 파일 경로 참조로 대체하고,
|
|
5
|
+
* 서버 전송 시 파일 경로를 실제 콘텐츠로 복원하는 기능을 제공합니다.
|
|
6
|
+
*
|
|
7
|
+
* report-publisher.ts 에서 사용합니다.
|
|
8
|
+
*/
|
|
9
|
+
import { readFileSync, existsSync, readdirSync } from "fs";
|
|
10
|
+
import { join, resolve } from "path";
|
|
11
|
+
/**
|
|
12
|
+
* 값이 파일 경로 참조인지 판별합니다.
|
|
13
|
+
* - "./"로 시작하고 줄바꿈이 없으면 파일 경로로 판별
|
|
14
|
+
* - SQL/JS/암호화 문자열은 "./"로 시작하지 않으므로 오판 없음
|
|
15
|
+
*/
|
|
16
|
+
export function isFilePath(value) {
|
|
17
|
+
if (!value || typeof value !== "string") {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
return value.startsWith("./") && !value.includes("\n");
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* ReportModel의 인라인 콘텐츠를 파일 경로 참조로 치환합니다.
|
|
24
|
+
* Pull/Save 응답을 로컬 .mtsd에 저장할 때 사용합니다.
|
|
25
|
+
*
|
|
26
|
+
* @param reportModel 서버에서 받은 전체 ReportModel (인라인 콘텐츠 포함)
|
|
27
|
+
* @param reportFolder 보고서 폴더 절대 경로 (.mtsd이 있는 폴더)
|
|
28
|
+
* @param reportCode 보고서 코드 (스크립트 파일명 탐색용)
|
|
29
|
+
* @returns 파일 경로 참조가 적용된 deep clone
|
|
30
|
+
*/
|
|
31
|
+
export function replaceContentWithFilePaths(reportModel, reportFolder, reportCode) {
|
|
32
|
+
const model = JSON.parse(JSON.stringify(reportModel));
|
|
33
|
+
// 1. ScriptText → 파일 경로
|
|
34
|
+
if (model.ScriptText && typeof model.ScriptText === "string" && model.ScriptText.trim().length > 0) {
|
|
35
|
+
const scriptFile = findScriptFile(reportFolder);
|
|
36
|
+
if (scriptFile) {
|
|
37
|
+
model.ScriptText = "./" + scriptFile;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// 2. ServerScriptText[] → 파일 경로
|
|
41
|
+
if (model.ServerScriptText && Array.isArray(model.ServerScriptText)) {
|
|
42
|
+
for (const ss of model.ServerScriptText) {
|
|
43
|
+
if (ss.ScriptText && typeof ss.ScriptText === "string" && ss.ScriptText.trim().length > 0) {
|
|
44
|
+
const ssFile = findServerScriptFile(reportFolder, ss.Name);
|
|
45
|
+
if (ssFile) {
|
|
46
|
+
ss.ScriptText = "./" + ssFile;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// 3. DataSources.Datas[] → 파일 경로
|
|
52
|
+
if (model.DataSources?.Datas && Array.isArray(model.DataSources.Datas)) {
|
|
53
|
+
for (const ds of model.DataSources.Datas) {
|
|
54
|
+
if (ds.SQL && typeof ds.SQL === "string" && ds.SQL.trim().length > 0) {
|
|
55
|
+
const dsFile = findDataSourceFile(reportFolder, ds.Name);
|
|
56
|
+
if (dsFile) {
|
|
57
|
+
ds.SQL = "./" + dsFile;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return model;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* ReportModel의 파일 경로 참조를 실제 파일 콘텐츠로 복원합니다.
|
|
66
|
+
* UploadReport(ZIP 빌드) 시 서버에 전송하기 전에 사용합니다.
|
|
67
|
+
* 인라인 콘텐츠(파일 경로가 아닌 값)는 그대로 유지됩니다.
|
|
68
|
+
*
|
|
69
|
+
* .ts 파일 경로인 경우 빌드된 .js를 outputFolder에서 읽습니다.
|
|
70
|
+
* .sql, .js, .json 파일은 소스 폴더에서 직접 읽습니다.
|
|
71
|
+
*
|
|
72
|
+
* @param reportModel 파일 경로 참조가 포함된 ReportModel
|
|
73
|
+
* @param reportFolder 보고서 소스 폴더 절대 경로
|
|
74
|
+
* @param outputFolder 빌드 출력 폴더 절대 경로 (.ts → .js 매핑용)
|
|
75
|
+
* @returns 인라인 콘텐츠가 복원된 deep clone
|
|
76
|
+
*/
|
|
77
|
+
export function resolveFilePathsToContent(reportModel, reportFolder, outputFolder) {
|
|
78
|
+
const model = JSON.parse(JSON.stringify(reportModel));
|
|
79
|
+
// 1. ScriptText — .script.ts → 빌드된 .script.js 읽기
|
|
80
|
+
if (isFilePath(model.ScriptText)) {
|
|
81
|
+
model.ScriptText = readResolvedFile(model.ScriptText, reportFolder, outputFolder);
|
|
82
|
+
}
|
|
83
|
+
// 2. ServerScriptText[]
|
|
84
|
+
if (model.ServerScriptText && Array.isArray(model.ServerScriptText)) {
|
|
85
|
+
for (const ss of model.ServerScriptText) {
|
|
86
|
+
if (isFilePath(ss.ScriptText)) {
|
|
87
|
+
ss.ScriptText = readResolvedFile(ss.ScriptText, reportFolder, outputFolder);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// 3. DataSources.Datas[]
|
|
92
|
+
if (model.DataSources?.Datas && Array.isArray(model.DataSources.Datas)) {
|
|
93
|
+
for (const ds of model.DataSources.Datas) {
|
|
94
|
+
if (isFilePath(ds.SQL)) {
|
|
95
|
+
ds.SQL = readResolvedFile(ds.SQL, reportFolder, outputFolder);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return model;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* 파일 경로 참조에서 실제 콘텐츠를 읽습니다.
|
|
103
|
+
* .ts 파일이면 outputFolder의 빌드된 .js를 읽고,
|
|
104
|
+
* 그 외(.sql, .js, .json 등)는 소스 폴더에서 직접 읽습니다.
|
|
105
|
+
*/
|
|
106
|
+
function readResolvedFile(refPath, reportFolder, outputFolder) {
|
|
107
|
+
if (refPath.toLowerCase().endsWith(".ts")) {
|
|
108
|
+
// .ts → 빌드 출력 폴더의 .js 파일 읽기
|
|
109
|
+
const jsRefPath = refPath.replace(/\.ts$/i, ".js");
|
|
110
|
+
const builtPath = resolve(outputFolder, jsRefPath);
|
|
111
|
+
if (existsSync(builtPath)) {
|
|
112
|
+
return readFileSync(builtPath, "utf-8");
|
|
113
|
+
}
|
|
114
|
+
// 빌드 파일이 없으면 에러
|
|
115
|
+
throw new Error(`빌드된 파일을 찾을 수 없습니다: ${jsRefPath}\n`
|
|
116
|
+
+ `경로: ${builtPath}\n`
|
|
117
|
+
+ "tsc 명령어로 빌드를 실행해 주세요.");
|
|
118
|
+
}
|
|
119
|
+
// .sql, .js, .json 등은 소스 폴더에서 직접 읽기
|
|
120
|
+
const fullPath = resolve(reportFolder, refPath);
|
|
121
|
+
if (!existsSync(fullPath)) {
|
|
122
|
+
throw new Error(`참조된 파일을 찾을 수 없습니다: ${refPath}\n경로: ${fullPath}`);
|
|
123
|
+
}
|
|
124
|
+
return readFileSync(fullPath, "utf-8");
|
|
125
|
+
}
|
|
126
|
+
// ─── 내부 헬퍼 함수 ────────────────────────────────────────
|
|
127
|
+
/** 보고서 폴더에서 .script.ts 또는 .script.js 파일을 찾습니다 */
|
|
128
|
+
function findScriptFile(reportFolder) {
|
|
129
|
+
if (!existsSync(reportFolder)) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
const files = readdirSync(reportFolder);
|
|
133
|
+
for (const f of files) {
|
|
134
|
+
const lower = f.toLowerCase();
|
|
135
|
+
if (lower.endsWith(".script.ts") || lower.endsWith(".script.js")) {
|
|
136
|
+
return f;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
/** ServerScript 폴더에서 해당 이름의 파일을 찾습니다 (.ts → .js → .json 우선순위) */
|
|
142
|
+
function findServerScriptFile(reportFolder, scriptName) {
|
|
143
|
+
const ssFolder = join(reportFolder, "ServerScript");
|
|
144
|
+
if (!existsSync(ssFolder)) {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
const safeName = sanitizeFileName(scriptName);
|
|
148
|
+
for (const ext of [".ts", ".js", ".json"]) {
|
|
149
|
+
const candidate = join(ssFolder, safeName + ext);
|
|
150
|
+
if (existsSync(candidate)) {
|
|
151
|
+
return "ServerScript/" + safeName + ext;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
/** DataSource 폴더에서 해당 이름의 파일을 찾습니다 (.sql → .ts → .js 우선순위) */
|
|
157
|
+
function findDataSourceFile(reportFolder, dsName) {
|
|
158
|
+
const dsFolder = join(reportFolder, "DataSource");
|
|
159
|
+
if (!existsSync(dsFolder)) {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
const safeName = sanitizeFileName(dsName);
|
|
163
|
+
for (const ext of [".sql", ".SQL", ".ts", ".js"]) {
|
|
164
|
+
const candidate = join(dsFolder, safeName + ext);
|
|
165
|
+
if (existsSync(candidate)) {
|
|
166
|
+
return "DataSource/" + safeName + ext;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
/** 파일명에서 Windows 금지 문자를 제거합니다 */
|
|
172
|
+
function sanitizeFileName(fileName) {
|
|
173
|
+
return fileName.replace(/[\\\/:*?"<>|]/g, "_");
|
|
174
|
+
}
|
|
@@ -10,11 +10,6 @@
|
|
|
10
10
|
* - ISaveReportModel 조립
|
|
11
11
|
* - 서버 응답으로 로컬 파일 업데이트
|
|
12
12
|
*/
|
|
13
|
-
export interface AudJson {
|
|
14
|
-
ReportCode: string;
|
|
15
|
-
ReportName?: string;
|
|
16
|
-
ModuleCode?: string;
|
|
17
|
-
}
|
|
18
13
|
export interface DataSourceItem {
|
|
19
14
|
Id?: string;
|
|
20
15
|
Name: string;
|
|
@@ -45,9 +40,7 @@ export declare function sanitizeFileName(fileName: string): string;
|
|
|
45
40
|
* outDir 기반으로 source → output 경로를 계산합니다.
|
|
46
41
|
*/
|
|
47
42
|
export declare function resolveOutputPath(reportPath: string, sourcePath?: string): string;
|
|
48
|
-
/** .
|
|
49
|
-
export declare function readAudJson(reportPath: string): AudJson;
|
|
50
|
-
/** .mtsd 또는 .sc 파일 읽기 */
|
|
43
|
+
/** 보고서 문서 파일 읽기 (.design.json → .mtsd → .sc 우선순위) */
|
|
51
44
|
export declare function readReportDocument(reportPath: string): any;
|
|
52
45
|
/**
|
|
53
46
|
* DataSource 파일 수집
|
|
@@ -89,7 +82,6 @@ export declare function writeReportResponse(reportPath: string, response: any):
|
|
|
89
82
|
* Extension의 writeReportInfo() + writeAudJson() 로직 재구현 (Pull 용)
|
|
90
83
|
*
|
|
91
84
|
* writeReportResponse와의 차이점:
|
|
92
|
-
* 1. .aud.json에 FolderCode, DocumentVersion, Description, ModifyDate, Modifier 추가 반영
|
|
93
85
|
* 2. JScript 파일이 없으면 서버에서 받은 JScript로 .script.js 생성
|
|
94
86
|
*/
|
|
95
87
|
export declare function writePullResponse(reportPath: string, response: any): string[];
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { readFileSync, existsSync, readdirSync, writeFileSync, mkdirSync } from "fs";
|
|
14
14
|
import { join, parse, resolve, dirname, extname, basename } from "path";
|
|
15
|
+
import { replaceContentWithFilePaths } from "./mtsd-file-ref.js";
|
|
15
16
|
// ─── Utility ───────────────────────────────────────────────
|
|
16
17
|
/** Windows 금지 문자를 _ 로 치환 */
|
|
17
18
|
export function sanitizeFileName(fileName) {
|
|
@@ -96,27 +97,24 @@ export function resolveOutputPath(reportPath, sourcePath) {
|
|
|
96
97
|
return join(resolvedOut, relativePart);
|
|
97
98
|
}
|
|
98
99
|
// ─── File Readers ──────────────────────────────────────────
|
|
99
|
-
/** .
|
|
100
|
-
export function readAudJson(reportPath) {
|
|
101
|
-
const configPath = join(reportPath, ".aud.json");
|
|
102
|
-
if (!existsSync(configPath)) {
|
|
103
|
-
throw new Error(`.aud.json 파일을 찾을 수 없습니다.\n경로: ${reportPath}`);
|
|
104
|
-
}
|
|
105
|
-
const text = readFileSync(configPath, "utf-8");
|
|
106
|
-
return JSON.parse(text);
|
|
107
|
-
}
|
|
108
|
-
/** .mtsd 또는 .sc 파일 읽기 */
|
|
100
|
+
/** 보고서 문서 파일 읽기 (.design.json → .mtsd → .sc 우선순위) */
|
|
109
101
|
export function readReportDocument(reportPath) {
|
|
102
|
+
// 1순위: .design.json (고정 파일명)
|
|
103
|
+
const designPath = join(reportPath, ".design.json");
|
|
104
|
+
if (existsSync(designPath)) {
|
|
105
|
+
const text = readFileSync(designPath, "utf-8");
|
|
106
|
+
return JSON.parse(text);
|
|
107
|
+
}
|
|
108
|
+
// 2순위: .mtsd, .sc
|
|
110
109
|
const files = readdirSync(reportPath);
|
|
111
110
|
for (const f of files) {
|
|
112
111
|
const lower = f.toLowerCase();
|
|
113
112
|
if (lower.endsWith(".mtsd") || lower.endsWith(".sc")) {
|
|
114
|
-
const
|
|
115
|
-
const text = readFileSync(filePath, "utf-8");
|
|
113
|
+
const text = readFileSync(join(reportPath, f), "utf-8");
|
|
116
114
|
return JSON.parse(text);
|
|
117
115
|
}
|
|
118
116
|
}
|
|
119
|
-
throw new Error("보고서 파일(.mtsd 또는 .sc)을 찾을 수 없습니다.");
|
|
117
|
+
throw new Error("보고서 파일(.design.json, .mtsd 또는 .sc)을 찾을 수 없습니다.");
|
|
120
118
|
}
|
|
121
119
|
/**
|
|
122
120
|
* DataSource 파일 수집
|
|
@@ -303,13 +301,15 @@ export function detectDeletedServerScripts(srcPath, outPath, reportDoc) {
|
|
|
303
301
|
*/
|
|
304
302
|
export function buildSaveModel(reportPath) {
|
|
305
303
|
const resolvedPath = resolve(reportPath);
|
|
306
|
-
// 1. .
|
|
307
|
-
const audJson = readAudJson(resolvedPath);
|
|
308
|
-
if (!audJson.ReportCode) {
|
|
309
|
-
throw new Error(".aud.json에 ReportCode가 없습니다.");
|
|
310
|
-
}
|
|
311
|
-
// 2. MTSD 문서 읽기
|
|
304
|
+
// 1. 보고서 문서 읽기 (.design.json → .mtsd → .sc)
|
|
312
305
|
const reportDoc = readReportDocument(resolvedPath);
|
|
306
|
+
const repInfo = reportDoc?.ReportInfo;
|
|
307
|
+
if (!repInfo?.ReportCode) {
|
|
308
|
+
throw new Error("보고서 문서에 ReportInfo.ReportCode가 없습니다.");
|
|
309
|
+
}
|
|
310
|
+
// 2. ModuleCode: ReportInfo.SavePath 확장자로 판별 (.sc → "SC", .mtsd → "SD")
|
|
311
|
+
const savePath = (repInfo.SavePath || "").toLowerCase();
|
|
312
|
+
const moduleCode = savePath.endsWith(".sc") ? "SC" : "SD";
|
|
313
313
|
// 3. .out 경로 해석
|
|
314
314
|
const outPath = resolveOutputPath(resolvedPath);
|
|
315
315
|
// 4. 파일 수집
|
|
@@ -321,9 +321,9 @@ export function buildSaveModel(reportPath) {
|
|
|
321
321
|
const deletedSS = detectDeletedServerScripts(resolvedPath, outPath, reportDoc);
|
|
322
322
|
// 6. 모델 조립
|
|
323
323
|
return {
|
|
324
|
-
REPORT_CODE:
|
|
325
|
-
MODULE_CODE:
|
|
326
|
-
REPORT_NAME:
|
|
324
|
+
REPORT_CODE: repInfo.ReportCode,
|
|
325
|
+
MODULE_CODE: moduleCode,
|
|
326
|
+
REPORT_NAME: repInfo.ReportName || repInfo.ReportCode,
|
|
327
327
|
JScript: jScript,
|
|
328
328
|
DataSource: dataSources,
|
|
329
329
|
ServerScript: serverScripts,
|
|
@@ -341,10 +341,10 @@ export function buildSaveModel(reportPath) {
|
|
|
341
341
|
export function writeReportResponse(reportPath, response) {
|
|
342
342
|
const resolvedPath = resolve(reportPath);
|
|
343
343
|
const written = [];
|
|
344
|
-
// 1. MTSD 파일
|
|
344
|
+
// 1. mtsd 경로 결정 (MTSD 쓰기는 모든 파일 생성 후 수행)
|
|
345
|
+
let mtsdPath = "";
|
|
345
346
|
if (response.ReportModel) {
|
|
346
347
|
const files = readdirSync(resolvedPath);
|
|
347
|
-
let mtsdPath = "";
|
|
348
348
|
for (const f of files) {
|
|
349
349
|
const lower = f.toLowerCase();
|
|
350
350
|
if (lower.endsWith(".mtsd") || lower.endsWith(".sc")) {
|
|
@@ -357,19 +357,6 @@ export function writeReportResponse(reportPath, response) {
|
|
|
357
357
|
const ext = moduleCode === "SC" ? ".sc" : ".mtsd";
|
|
358
358
|
mtsdPath = join(resolvedPath, (response.REPORT_CODE || "report") + ext);
|
|
359
359
|
}
|
|
360
|
-
writeFileSync(mtsdPath, JSON.stringify(response.ReportModel, null, " "), "utf-8");
|
|
361
|
-
written.push(mtsdPath);
|
|
362
|
-
// .aud.json 업데이트
|
|
363
|
-
const audJsonPath = join(resolvedPath, ".aud.json");
|
|
364
|
-
if (existsSync(audJsonPath)) {
|
|
365
|
-
const audJson = JSON.parse(readFileSync(audJsonPath, "utf-8"));
|
|
366
|
-
audJson.ReportCode = response.REPORT_CODE || audJson.ReportCode;
|
|
367
|
-
if (response.REPORT_NAME)
|
|
368
|
-
audJson.ReportName = response.REPORT_NAME;
|
|
369
|
-
if (response.MODULE_CODE)
|
|
370
|
-
audJson.ModuleCode = response.MODULE_CODE;
|
|
371
|
-
writeFileSync(audJsonPath, JSON.stringify(audJson, null, " "), "utf-8");
|
|
372
|
-
}
|
|
373
360
|
}
|
|
374
361
|
// 2. 새 DataSource 파일 생성 (이미 존재하면 skip)
|
|
375
362
|
if (response.DataSource && response.DataSource.length > 0) {
|
|
@@ -399,6 +386,17 @@ export function writeReportResponse(reportPath, response) {
|
|
|
399
386
|
}
|
|
400
387
|
}
|
|
401
388
|
}
|
|
389
|
+
// 4. 모든 파일 생성 후 .mtsd + .design.json 저장
|
|
390
|
+
if (response.ReportModel && mtsdPath) {
|
|
391
|
+
// .mtsd — 서버 원본 그대로 저장
|
|
392
|
+
writeFileSync(mtsdPath, JSON.stringify(response.ReportModel, null, " "), "utf-8");
|
|
393
|
+
written.push(mtsdPath);
|
|
394
|
+
// .design.json — 파일 경로 참조 버전 저장 (AI/개발용)
|
|
395
|
+
const designModel = replaceContentWithFilePaths(response.ReportModel, resolvedPath, response.REPORT_CODE || "");
|
|
396
|
+
const designPath = join(resolvedPath, ".design.json");
|
|
397
|
+
writeFileSync(designPath, JSON.stringify(designModel, null, " "), "utf-8");
|
|
398
|
+
written.push(designPath);
|
|
399
|
+
}
|
|
402
400
|
return written;
|
|
403
401
|
}
|
|
404
402
|
// ─── Pull Response Writer ──────────────────────────────────
|
|
@@ -407,16 +405,15 @@ export function writeReportResponse(reportPath, response) {
|
|
|
407
405
|
* Extension의 writeReportInfo() + writeAudJson() 로직 재구현 (Pull 용)
|
|
408
406
|
*
|
|
409
407
|
* writeReportResponse와의 차이점:
|
|
410
|
-
* 1. .aud.json에 FolderCode, DocumentVersion, Description, ModifyDate, Modifier 추가 반영
|
|
411
408
|
* 2. JScript 파일이 없으면 서버에서 받은 JScript로 .script.js 생성
|
|
412
409
|
*/
|
|
413
410
|
export function writePullResponse(reportPath, response) {
|
|
414
411
|
const resolvedPath = resolve(reportPath);
|
|
415
412
|
const written = [];
|
|
416
|
-
// 1. MTSD 파일
|
|
413
|
+
// 1. mtsd 경로 결정 (MTSD 쓰기는 모든 파일 생성 후 수행)
|
|
414
|
+
let mtsdPath = "";
|
|
417
415
|
if (response.ReportModel) {
|
|
418
416
|
const files = readdirSync(resolvedPath);
|
|
419
|
-
let mtsdPath = "";
|
|
420
417
|
for (const f of files) {
|
|
421
418
|
const lower = f.toLowerCase();
|
|
422
419
|
if (lower.endsWith(".mtsd") || lower.endsWith(".sc")) {
|
|
@@ -429,25 +426,6 @@ export function writePullResponse(reportPath, response) {
|
|
|
429
426
|
const ext = moduleCode === "SC" ? ".sc" : ".mtsd";
|
|
430
427
|
mtsdPath = join(resolvedPath, (response.REPORT_CODE || "report") + ext);
|
|
431
428
|
}
|
|
432
|
-
writeFileSync(mtsdPath, JSON.stringify(response.ReportModel, null, " "), "utf-8");
|
|
433
|
-
written.push(mtsdPath);
|
|
434
|
-
// .aud.json 업데이트 (Pull은 서버 ReportInfo의 모든 메타데이터 반영)
|
|
435
|
-
const audJsonPath = join(resolvedPath, ".aud.json");
|
|
436
|
-
const repInfo = response.ReportModel?.ReportInfo;
|
|
437
|
-
if (repInfo) {
|
|
438
|
-
const audJson = {
|
|
439
|
-
ReportCode: response.REPORT_CODE || "",
|
|
440
|
-
ReportName: repInfo.ReportName || "",
|
|
441
|
-
FolderCode: repInfo.FolderCode || "",
|
|
442
|
-
ModuleCode: response.MODULE_CODE || "",
|
|
443
|
-
DocumentVersion: repInfo.DocumentVersion || "",
|
|
444
|
-
Description: repInfo.Description || "",
|
|
445
|
-
ModifyDate: repInfo.EditDate || "",
|
|
446
|
-
Modifier: repInfo.Editor || "",
|
|
447
|
-
};
|
|
448
|
-
writeFileSync(audJsonPath, JSON.stringify(audJson, null, " "), "utf-8");
|
|
449
|
-
written.push(audJsonPath);
|
|
450
|
-
}
|
|
451
429
|
}
|
|
452
430
|
// 2. 새 DataSource 파일 생성 (이미 존재하면 skip)
|
|
453
431
|
if (response.DataSource && response.DataSource.length > 0) {
|
|
@@ -492,6 +470,17 @@ export function writePullResponse(reportPath, response) {
|
|
|
492
470
|
writeFileSync(scriptPath, response.JScript, "utf-8");
|
|
493
471
|
written.push(scriptPath);
|
|
494
472
|
}
|
|
473
|
+
// 5. 모든 파일 생성 후 .mtsd + .design.json 저장
|
|
474
|
+
if (response.ReportModel && mtsdPath) {
|
|
475
|
+
// .mtsd — 서버 원본 그대로 저장
|
|
476
|
+
writeFileSync(mtsdPath, JSON.stringify(response.ReportModel, null, " "), "utf-8");
|
|
477
|
+
written.push(mtsdPath);
|
|
478
|
+
// .design.json — 파일 경로 참조 버전 저장 (AI/개발용)
|
|
479
|
+
const designModel = replaceContentWithFilePaths(response.ReportModel, resolvedPath, response.REPORT_CODE || "");
|
|
480
|
+
const designPath = join(resolvedPath, ".design.json");
|
|
481
|
+
writeFileSync(designPath, JSON.stringify(designModel, null, " "), "utf-8");
|
|
482
|
+
written.push(designPath);
|
|
483
|
+
}
|
|
495
484
|
return written;
|
|
496
485
|
}
|
|
497
486
|
// ─── Helpers (private) ─────────────────────────────────────
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bimatrix-aud-platform/aud_mcp_server",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.56",
|
|
4
4
|
"description": "MCP Server for i-AUD MTSD document validation, generation, schema querying, control info extraction, and database operations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -15,9 +15,9 @@ export interface IMTSDDocument {
|
|
|
15
15
|
ReportInfo: IReportInfo;
|
|
16
16
|
/** 보고서에서 사용하는 데이터소스 목록 */
|
|
17
17
|
DataSources: IDataSources;
|
|
18
|
-
/** 클라이언트에서 실행되는 JavaScript
|
|
18
|
+
/** 클라이언트에서 실행되는 JavaScript 코드. 로컬 .mtsd에서는 상대 경로 참조(예: "./report.script.ts")가 될 수 있음 */
|
|
19
19
|
ScriptText: string;
|
|
20
|
-
/** 서버에서 실행되는 JavaScript 코드
|
|
20
|
+
/** 서버에서 실행되는 JavaScript 코드 배열. 각 항목의 ScriptText가 로컬에서 상대 경로(예: "./ServerScript/@name.ts")가 될 수 있음 */
|
|
21
21
|
ServerScriptText: IServerScript[];
|
|
22
22
|
/** 화면 양식(탭) 목록 */
|
|
23
23
|
Forms: IForm[];
|
|
@@ -117,7 +117,7 @@ export interface IDataSource {
|
|
|
117
117
|
Encrypted: boolean;
|
|
118
118
|
/** 데이터소스 타입 (0:메타 템플릿,1:메타 쿼리, 2:일반 SQL,3:OLAP Drill to Detail,4:공통데이터소스,5:메타 필터) */
|
|
119
119
|
DSType: number;
|
|
120
|
-
/** 실행할 SQL
|
|
120
|
+
/** 실행할 SQL 쿼리문. 로컬 .mtsd에서는 상대 경로 참조(예: "./DataSource/name.sql")가 될 수 있음 */
|
|
121
121
|
SQL: string;
|
|
122
122
|
/** SQL 파라미터 배열 */
|
|
123
123
|
Params: IDataSourceParam[];
|
|
@@ -160,7 +160,7 @@ export interface IServerScript {
|
|
|
160
160
|
Key: string;
|
|
161
161
|
/** 스크립트 암호화 여부 */
|
|
162
162
|
Encrypted: boolean;
|
|
163
|
-
/** 스크립트 본문 (JavaScript 코드) */
|
|
163
|
+
/** 스크립트 본문 (JavaScript 코드). 로컬 .mtsd에서는 상대 경로 참조(예: "./ServerScript/@name.ts")가 될 수 있음 */
|
|
164
164
|
ScriptText: string;
|
|
165
165
|
}
|
|
166
166
|
|
package/schemas/mtsd.schema.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"properties": {
|
|
9
9
|
"ReportInfo": { "$ref": "#/$defs/ReportInfo" },
|
|
10
10
|
"DataSources": { "$ref": "#/$defs/DataSources" },
|
|
11
|
-
"ScriptText": { "type": "string", "description": "클라이언트에서 실행되는 JavaScript
|
|
11
|
+
"ScriptText": { "type": "string", "description": "클라이언트에서 실행되는 JavaScript 코드. 로컬에서는 상대 경로 참조(예: ./report.script.ts)가 될 수 있음" },
|
|
12
12
|
"ServerScriptText": {
|
|
13
13
|
"type": "array",
|
|
14
14
|
"items": { "$ref": "#/$defs/ServerScript" },
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
"ConnectionCode": { "type": "string", "description": "연결된 DB 커넥션 코드" },
|
|
108
108
|
"Encrypted": { "type": "boolean", "description": "SQL 쿼리 암호화 여부" },
|
|
109
109
|
"DSType": { "type": "integer", "enum": [0, 1, 2, 3,4,5], "description": "데이터소스 타입 (0:메타 템플릿,1:메타 쿼리, 2:일반 SQL,3:OLAP Drill to Detail,4:공통데이터소스,5:메타 필터)" },
|
|
110
|
-
"SQL": { "type": "string", "description": "실행할 SQL
|
|
110
|
+
"SQL": { "type": "string", "description": "실행할 SQL 쿼리문. 로컬에서는 상대 경로 참조(예: ./DataSource/name.sql)가 될 수 있음" },
|
|
111
111
|
"Params": {
|
|
112
112
|
"type": "array",
|
|
113
113
|
"items": { "$ref": "#/$defs/DataSourceParam" }
|
|
@@ -144,7 +144,7 @@
|
|
|
144
144
|
"Name": { "type": "string", "description": "스크립트명" },
|
|
145
145
|
"Key": { "type": "string", "description": "스크립트 키 (고유 식별자)" },
|
|
146
146
|
"Encrypted": { "type": "boolean", "description": "스크립트 암호화 여부" },
|
|
147
|
-
"ScriptText": { "type": "string", "description": "스크립트 본문 (JavaScript 코드)" }
|
|
147
|
+
"ScriptText": { "type": "string", "description": "스크립트 본문 (JavaScript 코드). 로컬에서는 상대 경로 참조(예: ./ServerScript/@name.ts)가 될 수 있음" }
|
|
148
148
|
}
|
|
149
149
|
},
|
|
150
150
|
"Form": {
|