workday-studio-mcp-server 2.0.1 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +21 -1
- package/dist/index.js.map +1 -1
- package/dist/tools/add-assembly-step.d.ts +7 -0
- package/dist/tools/add-assembly-step.d.ts.map +1 -0
- package/dist/tools/add-assembly-step.js +130 -0
- package/dist/tools/add-assembly-step.js.map +1 -0
- package/dist/tools/create-project.d.ts +3 -0
- package/dist/tools/create-project.d.ts.map +1 -0
- package/dist/tools/create-project.js +262 -0
- package/dist/tools/create-project.js.map +1 -0
- package/dist/tools/create-xsl-transform.d.ts +6 -0
- package/dist/tools/create-xsl-transform.d.ts.map +1 -0
- package/dist/tools/create-xsl-transform.js +103 -0
- package/dist/tools/create-xsl-transform.js.map +1 -0
- package/dist/tools/get-step-type-reference.d.ts +6 -0
- package/dist/tools/get-step-type-reference.d.ts.map +1 -0
- package/dist/tools/get-step-type-reference.js +387 -0
- package/dist/tools/get-step-type-reference.js.map +1 -0
- package/dist/tools/log-learning.d.ts +6 -0
- package/dist/tools/log-learning.d.ts.map +1 -0
- package/dist/tools/log-learning.js +77 -0
- package/dist/tools/log-learning.js.map +1 -0
- package/dist/tools/lookup-soap-operations.d.ts +6 -0
- package/dist/tools/lookup-soap-operations.d.ts.map +1 -0
- package/dist/tools/lookup-soap-operations.js +343 -0
- package/dist/tools/lookup-soap-operations.js.map +1 -0
- package/dist/tools/parse-server-log.d.ts +6 -0
- package/dist/tools/parse-server-log.d.ts.map +1 -0
- package/dist/tools/parse-server-log.js +252 -0
- package/dist/tools/parse-server-log.js.map +1 -0
- package/dist/tools/plan-integration.d.ts +9 -0
- package/dist/tools/plan-integration.d.ts.map +1 -0
- package/dist/tools/plan-integration.js +550 -0
- package/dist/tools/plan-integration.js.map +1 -0
- package/dist/tools/update-sub-flow.d.ts +7 -0
- package/dist/tools/update-sub-flow.d.ts.map +1 -0
- package/dist/tools/update-sub-flow.js +185 -0
- package/dist/tools/update-sub-flow.js.map +1 -0
- package/dist/tools/validate-assembly.d.ts +6 -0
- package/dist/tools/validate-assembly.d.ts.map +1 -0
- package/dist/tools/validate-assembly.js +94 -0
- package/dist/tools/validate-assembly.js.map +1 -0
- package/dist/utils/assembly-validator.d.ts +18 -0
- package/dist/utils/assembly-validator.d.ts.map +1 -0
- package/dist/utils/assembly-validator.js +202 -0
- package/dist/utils/assembly-validator.js.map +1 -0
- package/dist/utils/fs.d.ts +6 -1
- package/dist/utils/fs.d.ts.map +1 -1
- package/dist/utils/fs.js +16 -1
- package/dist/utils/fs.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* update_sub_flow — replace the <cc:steps> body of a named sub-flow in assembly.xml.
|
|
3
|
+
* Ported from the reference implementation (update-sub-flow.mjs).
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { readFile, writeFile } from 'fs/promises';
|
|
7
|
+
import { join, resolve } from 'path';
|
|
8
|
+
import { existsSync } from 'fs';
|
|
9
|
+
import { getConfig } from '../config.js';
|
|
10
|
+
import { errorResponse } from '../utils/errors.js';
|
|
11
|
+
import { validateAssembly, checkDiagramDrift } from '../utils/assembly-validator.js';
|
|
12
|
+
import { backupFile } from '../utils/fs.js';
|
|
13
|
+
import { validateXml } from '../utils/xml.js';
|
|
14
|
+
export function register(server) {
|
|
15
|
+
server.tool('update_sub_flow', [
|
|
16
|
+
'Replaces the <cc:steps> body of a named sub-flow in assembly.xml.',
|
|
17
|
+
'Use this to fill in a TODO stub generated by plan_integration.',
|
|
18
|
+
'',
|
|
19
|
+
'Finds <cc:async-mediation id="Do{sub_flow_id}"> and replaces its <cc:steps>',
|
|
20
|
+
'content with steps_xml. Everything else on the async-mediation is preserved:',
|
|
21
|
+
'routes-to, handle-downstream-errors, and the trailing <cc:send-error>.',
|
|
22
|
+
'',
|
|
23
|
+
'steps_xml format:',
|
|
24
|
+
' - Provide the step elements that go INSIDE <cc:steps>. Do not include the wrapper.',
|
|
25
|
+
' - Use \\t for tabs. Steps should sit at 4-tab depth (matching skeleton indent).',
|
|
26
|
+
' - Example for a RAAS fetch + eval:',
|
|
27
|
+
' \\t\\t\\t\\t<cc:workday-out-rest id="GetWorkers" routes-response-to="TODO_next"',
|
|
28
|
+
' \\t\\t\\t\\t extra-path="@{intsys.reportService.getExtrapath(\'alias\')}"/>',
|
|
29
|
+
'',
|
|
30
|
+
'TOP-LEVEL ELEMENTS WARNING (Studio schema rule confirmed INT095, INT069, INT144):',
|
|
31
|
+
'The following elements CANNOT appear inside steps_xml — they MUST be top-level',
|
|
32
|
+
'elements placed directly inside <cc:assembly>, not inside <cc:steps>:',
|
|
33
|
+
' - cc:workday-out-rest',
|
|
34
|
+
' - cc:splitter',
|
|
35
|
+
' - cc:http-out',
|
|
36
|
+
' - cc:email-out',
|
|
37
|
+
' - cc:workday-out-soap',
|
|
38
|
+
'If your sub-flow needs to call any of these, place them as top-level elements in',
|
|
39
|
+
'the assembly and chain to them via routes-to on the async-mediation itself.',
|
|
40
|
+
'The validate_assembly tool will catch this mistake automatically.',
|
|
41
|
+
'',
|
|
42
|
+
'A .bak backup is written before every change.',
|
|
43
|
+
'XML well-formedness is validated before the write is committed.',
|
|
44
|
+
'',
|
|
45
|
+
'To also change the routes-to on the async-mediation itself (e.g. from',
|
|
46
|
+
'"EndGetWorkers" to "Splitter"), use write_integration_file for a full rewrite.',
|
|
47
|
+
].join('\n'), {
|
|
48
|
+
project_name: z.string()
|
|
49
|
+
.describe('Project name, e.g. "INT145_My_Integration"'),
|
|
50
|
+
sub_flow_id: z.string()
|
|
51
|
+
.describe('Base id used in plan_integration, e.g. "GetWorkers" (NOT "DoGetWorkers"). The tool looks for id="Do{sub_flow_id}" in the assembly.'),
|
|
52
|
+
steps_xml: z.string()
|
|
53
|
+
.describe('New step elements for inside <cc:steps>. Omit the <cc:steps> wrapper. Use \\t for tabs at 4-tab depth.'),
|
|
54
|
+
}, async ({ project_name, sub_flow_id, steps_xml }) => {
|
|
55
|
+
const cfg = getConfig();
|
|
56
|
+
const projectPath = resolve(cfg.workspacePath, project_name);
|
|
57
|
+
const assemblyPath = join(projectPath, 'ws', 'WSAR-INF', 'assembly.xml');
|
|
58
|
+
if (!existsSync(assemblyPath)) {
|
|
59
|
+
return errorResponse('FILE_NOT_FOUND', `assembly.xml not found in project '${project_name}'.`, 'Run plan_integration first to generate the skeleton.');
|
|
60
|
+
}
|
|
61
|
+
let original;
|
|
62
|
+
try {
|
|
63
|
+
original = await readFile(assemblyPath, 'utf-8');
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
return errorResponse('READ_ERROR', e.message, null);
|
|
67
|
+
}
|
|
68
|
+
const result = replaceStepsBlock(original, sub_flow_id, steps_xml);
|
|
69
|
+
if (!result.ok) {
|
|
70
|
+
return errorResponse(result.code, result.message, result.suggestion);
|
|
71
|
+
}
|
|
72
|
+
const xmlValidation = validateXml(result.xml);
|
|
73
|
+
if (!xmlValidation.valid) {
|
|
74
|
+
return errorResponse('INVALID_XML', `The replacement would produce malformed XML: ${xmlValidation.errors.join('; ')}`, 'Check steps_xml for unclosed tags, unescaped & characters (use &), or missing wd: namespace prefixes.');
|
|
75
|
+
}
|
|
76
|
+
const backupPath = await backupFile(assemblyPath);
|
|
77
|
+
try {
|
|
78
|
+
await writeFile(assemblyPath, result.xml, 'utf-8');
|
|
79
|
+
}
|
|
80
|
+
catch (e) {
|
|
81
|
+
return errorResponse('WRITE_FAILED', e.message, null);
|
|
82
|
+
}
|
|
83
|
+
// Studio-specific validation
|
|
84
|
+
const wsDir = join(projectPath, 'ws', 'WSAR-INF');
|
|
85
|
+
const issues = validateAssembly(result.xml, wsDir);
|
|
86
|
+
const errors = issues.filter(i => i.severity === 'ERROR');
|
|
87
|
+
const warnings = issues.filter(i => i.severity === 'WARNING');
|
|
88
|
+
// Diagram drift detection
|
|
89
|
+
const diagramPath = join(wsDir, 'assembly-diagram.xml');
|
|
90
|
+
let diagramDrift = null;
|
|
91
|
+
if (existsSync(diagramPath)) {
|
|
92
|
+
let diagramXml = null;
|
|
93
|
+
try {
|
|
94
|
+
diagramXml = await readFile(diagramPath, 'utf8');
|
|
95
|
+
}
|
|
96
|
+
catch { /* non-fatal */ }
|
|
97
|
+
if (diagramXml) {
|
|
98
|
+
const drifted = checkDiagramDrift(result.xml, diagramXml);
|
|
99
|
+
if (drifted.length > 0) {
|
|
100
|
+
diagramDrift = {
|
|
101
|
+
warning: `${drifted.length} element(s) in assembly.xml have no matching entry in assembly-diagram.xml.`,
|
|
102
|
+
missing_from_diagram: drifted.map(d => `${d.tag} id="${d.id}"`),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const backup = backupPath
|
|
108
|
+
? 'ws/WSAR-INF/' + backupPath.split('/WSAR-INF/').pop()
|
|
109
|
+
: null;
|
|
110
|
+
return {
|
|
111
|
+
content: [{
|
|
112
|
+
type: 'text',
|
|
113
|
+
text: JSON.stringify({
|
|
114
|
+
success: true,
|
|
115
|
+
updated: `Do${sub_flow_id}`,
|
|
116
|
+
backup,
|
|
117
|
+
validation: {
|
|
118
|
+
clean: issues.length === 0,
|
|
119
|
+
errors: errors.length,
|
|
120
|
+
warnings: warnings.length,
|
|
121
|
+
issues: issues.length > 0 ? issues : undefined,
|
|
122
|
+
},
|
|
123
|
+
...(diagramDrift ? { diagram_drift: diagramDrift } : {}),
|
|
124
|
+
next_step: errors.length > 0
|
|
125
|
+
? 'Fix the ERRORs above before opening in Studio.'
|
|
126
|
+
: diagramDrift
|
|
127
|
+
? 'Assembly valid. Update assembly-diagram.xml to add missing diagram entries before opening in Studio.'
|
|
128
|
+
: 'Open assembly-diagram.xml in Studio to verify the diagram renders correctly.',
|
|
129
|
+
}, null, 2),
|
|
130
|
+
}],
|
|
131
|
+
};
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
function replaceStepsBlock(xml, subFlowId, newStepsContent) {
|
|
135
|
+
const asyncMedTag = `<cc:async-mediation id="Do${subFlowId}"`;
|
|
136
|
+
const asyncMedStart = xml.indexOf(asyncMedTag);
|
|
137
|
+
if (asyncMedStart === -1) {
|
|
138
|
+
return {
|
|
139
|
+
ok: false,
|
|
140
|
+
code: 'SUB_FLOW_NOT_FOUND',
|
|
141
|
+
message: `No element with id="Do${subFlowId}" found in assembly.xml.`,
|
|
142
|
+
suggestion: `Check that sub_flow_id matches exactly what was passed to plan_integration. Run list_assembly_steps to see available ids.`,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
const stepsOpenTag = '<cc:steps>';
|
|
146
|
+
const stepsCloseTag = '</cc:steps>';
|
|
147
|
+
const stepsOpenIdx = xml.indexOf(stepsOpenTag, asyncMedStart);
|
|
148
|
+
if (stepsOpenIdx === -1) {
|
|
149
|
+
return {
|
|
150
|
+
ok: false,
|
|
151
|
+
code: 'STEPS_NOT_FOUND',
|
|
152
|
+
message: `No <cc:steps> found inside Do${subFlowId}.`,
|
|
153
|
+
suggestion: 'The assembly.xml may have been manually modified. Check the file with read_integration_file.',
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
// Guard: no other async-mediation should appear between our tag and the steps open
|
|
157
|
+
const between = xml.substring(asyncMedStart + asyncMedTag.length, stepsOpenIdx);
|
|
158
|
+
if (between.includes('<cc:async-mediation')) {
|
|
159
|
+
return {
|
|
160
|
+
ok: false,
|
|
161
|
+
code: 'AMBIGUOUS_TARGET',
|
|
162
|
+
message: `Found an unexpected nested async-mediation before <cc:steps> in Do${subFlowId}.`,
|
|
163
|
+
suggestion: 'Use write_integration_file for a full rewrite instead.',
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
const stepsCloseIdx = xml.indexOf(stepsCloseTag, stepsOpenIdx + stepsOpenTag.length);
|
|
167
|
+
if (stepsCloseIdx === -1) {
|
|
168
|
+
return {
|
|
169
|
+
ok: false,
|
|
170
|
+
code: 'STEPS_UNCLOSED',
|
|
171
|
+
message: `No </cc:steps> closing tag found after <cc:steps> in Do${subFlowId}.`,
|
|
172
|
+
suggestion: 'assembly.xml may be malformed. Validate with validate_xml_file.',
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
// Detect the indentation of <cc:steps> so the closing tag stays aligned
|
|
176
|
+
const lineStart = xml.lastIndexOf('\n', stepsOpenIdx) + 1;
|
|
177
|
+
const stepsIndent = xml.substring(lineStart, stepsOpenIdx);
|
|
178
|
+
const before = xml.substring(0, stepsOpenIdx + stepsOpenTag.length);
|
|
179
|
+
const after = xml.substring(stepsCloseIdx); // starts with </cc:steps>
|
|
180
|
+
return {
|
|
181
|
+
ok: true,
|
|
182
|
+
xml: `${before}\n${newStepsContent}\n${stepsIndent}${after}`,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=update-sub-flow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-sub-flow.js","sourceRoot":"","sources":["../../src/tools/update-sub-flow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* validate_assembly — run Studio-specific validation rules on a project's assembly.xml.
|
|
3
|
+
*/
|
|
4
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
5
|
+
export declare function register(server: McpServer): void;
|
|
6
|
+
//# sourceMappingURL=validate-assembly.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-assembly.d.ts","sourceRoot":"","sources":["../../src/tools/validate-assembly.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKzE,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA4FhD"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* validate_assembly — run Studio-specific validation rules on a project's assembly.xml.
|
|
3
|
+
*/
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { readFile } from 'fs/promises';
|
|
6
|
+
import { join, resolve } from 'path';
|
|
7
|
+
import { existsSync } from 'fs';
|
|
8
|
+
import { getConfig } from '../config.js';
|
|
9
|
+
import { errorResponse } from '../utils/errors.js';
|
|
10
|
+
import { validateAssembly, checkDiagramDrift } from '../utils/assembly-validator.js';
|
|
11
|
+
export function register(server) {
|
|
12
|
+
server.tool('validate_assembly', [
|
|
13
|
+
'Run Workday Studio-specific validation rules on a project\'s assembly.xml.',
|
|
14
|
+
'',
|
|
15
|
+
'Checks rules that XML well-formedness alone cannot catch:',
|
|
16
|
+
' • No XML comments (they shift @mixed indices and break diagram connections)',
|
|
17
|
+
' • All routes-to / routes-response-to targets exist',
|
|
18
|
+
' • vm:// sub-flow endpoints resolve to real cc:local-in elements',
|
|
19
|
+
' • Required attributes present (application=, version=, extra-path=, url=)',
|
|
20
|
+
' • Top-level-only elements not nested inside <cc:steps>',
|
|
21
|
+
' • cc:splitter has no routes-to attribute',
|
|
22
|
+
' • XSL files referenced by url= exist in WSAR-INF',
|
|
23
|
+
' • cc:note is not used (schema-invalid + crashes Studio diagram)',
|
|
24
|
+
' • No TODO_ stub ids remaining',
|
|
25
|
+
'',
|
|
26
|
+
'Set check_diagram_drift=true to also compare assembly.xml element ids',
|
|
27
|
+
'against assembly-diagram.xml and report any renderable elements missing',
|
|
28
|
+
'from the diagram.',
|
|
29
|
+
].join('\n'), {
|
|
30
|
+
project_name: z.string().describe('Studio project name.'),
|
|
31
|
+
check_diagram_drift: z.boolean().optional().describe('Also check for assembly elements missing from the diagram (default: false).'),
|
|
32
|
+
}, async ({ project_name, check_diagram_drift = false }) => {
|
|
33
|
+
const cfg = getConfig();
|
|
34
|
+
const wsarInfPath = resolve(cfg.workspacePath, project_name, 'ws', 'WSAR-INF');
|
|
35
|
+
const assemblyPath = join(wsarInfPath, 'assembly.xml');
|
|
36
|
+
const diagramPath = join(wsarInfPath, 'assembly-diagram.xml');
|
|
37
|
+
if (!existsSync(assemblyPath)) {
|
|
38
|
+
return errorResponse('ASSEMBLY_NOT_FOUND', `assembly.xml not found for project '${project_name}'.`, 'Check the project name or create the project first.');
|
|
39
|
+
}
|
|
40
|
+
let assemblyXml;
|
|
41
|
+
try {
|
|
42
|
+
assemblyXml = await readFile(assemblyPath, 'utf8');
|
|
43
|
+
}
|
|
44
|
+
catch (e) {
|
|
45
|
+
return errorResponse('READ_ERROR', e.message, null);
|
|
46
|
+
}
|
|
47
|
+
// Run assembly validation (pass wsarInfPath so XSL file checks work)
|
|
48
|
+
const issues = validateAssembly(assemblyXml, wsarInfPath);
|
|
49
|
+
const errors = issues.filter(i => i.severity === 'ERROR');
|
|
50
|
+
const warnings = issues.filter(i => i.severity === 'WARNING');
|
|
51
|
+
const infos = issues.filter(i => i.severity === 'INFO');
|
|
52
|
+
// Optional diagram drift check
|
|
53
|
+
let diagramDrift = null;
|
|
54
|
+
if (check_diagram_drift) {
|
|
55
|
+
if (existsSync(diagramPath)) {
|
|
56
|
+
try {
|
|
57
|
+
const diagramXml = await readFile(diagramPath, 'utf8');
|
|
58
|
+
diagramDrift = checkDiagramDrift(assemblyXml, diagramXml);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
diagramDrift = null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
diagramDrift = [];
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const result = {
|
|
69
|
+
project: project_name,
|
|
70
|
+
assembly_path: `ws/WSAR-INF/assembly.xml`,
|
|
71
|
+
summary: {
|
|
72
|
+
errors: errors.length,
|
|
73
|
+
warnings: warnings.length,
|
|
74
|
+
infos: infos.length,
|
|
75
|
+
total_issues: issues.length,
|
|
76
|
+
status: errors.length > 0 ? 'FAIL' : warnings.length > 0 ? 'WARN' : 'PASS',
|
|
77
|
+
},
|
|
78
|
+
issues: issues.length > 0 ? issues : [],
|
|
79
|
+
};
|
|
80
|
+
if (diagramDrift !== null) {
|
|
81
|
+
result['diagram_drift'] = {
|
|
82
|
+
missing_from_diagram: diagramDrift.length,
|
|
83
|
+
elements: diagramDrift,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
content: [{
|
|
88
|
+
type: 'text',
|
|
89
|
+
text: JSON.stringify(result, null, 2),
|
|
90
|
+
}],
|
|
91
|
+
};
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=validate-assembly.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-assembly.js","sourceRoot":"","sources":["../../src/tools/validate-assembly.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Studio assembly validator — checks rules that XML well-formedness alone cannot catch.
|
|
3
|
+
*
|
|
4
|
+
* Returns an array of { severity, code, message } objects.
|
|
5
|
+
* severity: 'ERROR' (will break Studio) | 'WARNING' (will cause runtime failures) | 'INFO' (awareness)
|
|
6
|
+
*/
|
|
7
|
+
export interface AssemblyIssue {
|
|
8
|
+
severity: 'ERROR' | 'WARNING' | 'INFO';
|
|
9
|
+
code: string;
|
|
10
|
+
message: string;
|
|
11
|
+
}
|
|
12
|
+
export interface DiagramDriftItem {
|
|
13
|
+
tag: string;
|
|
14
|
+
id: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function validateAssembly(xml: string, wsDir?: string | null): AssemblyIssue[];
|
|
17
|
+
export declare function checkDiagramDrift(assemblyXml: string, diagramXml: string): DiagramDriftItem[];
|
|
18
|
+
//# sourceMappingURL=assembly-validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assembly-validator.d.ts","sourceRoot":"","sources":["../../src/utils/assembly-validator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,GAAE,MAAM,GAAG,IAAW,GAAG,aAAa,EAAE,CAc1F;AA2LD,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAa7F"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Studio assembly validator — checks rules that XML well-formedness alone cannot catch.
|
|
3
|
+
*
|
|
4
|
+
* Returns an array of { severity, code, message } objects.
|
|
5
|
+
* severity: 'ERROR' (will break Studio) | 'WARNING' (will cause runtime failures) | 'INFO' (awareness)
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync } from 'fs';
|
|
8
|
+
import { join } from 'path';
|
|
9
|
+
export function validateAssembly(xml, wsDir = null) {
|
|
10
|
+
const issues = [];
|
|
11
|
+
checkNoXmlComments(xml, issues);
|
|
12
|
+
checkBrokenRoutes(xml, issues);
|
|
13
|
+
checkLocalOutEndpoints(xml, issues);
|
|
14
|
+
checkRequiredAttributes(xml, issues);
|
|
15
|
+
checkTopLevelOnlyElements(xml, issues);
|
|
16
|
+
checkSplitterRoutes(xml, issues);
|
|
17
|
+
if (wsDir)
|
|
18
|
+
checkXslFileReferences(xml, wsDir, issues);
|
|
19
|
+
checkCcNote(xml, issues);
|
|
20
|
+
checkTodoStubs(xml, issues);
|
|
21
|
+
return issues;
|
|
22
|
+
}
|
|
23
|
+
// ─── Rule: no XML comments in assembly.xml ────────────────────────────────────
|
|
24
|
+
// Comments are valid XML but shift @mixed indices, breaking all diagram EMF XPath references.
|
|
25
|
+
function checkNoXmlComments(xml, issues) {
|
|
26
|
+
const matches = [...xml.matchAll(/<!--/g)];
|
|
27
|
+
if (matches.length > 0) {
|
|
28
|
+
issues.push({
|
|
29
|
+
severity: 'ERROR',
|
|
30
|
+
code: 'XML_COMMENTS_PRESENT',
|
|
31
|
+
message: `Found ${matches.length} XML comment(s). Comments shift @mixed indices and break all diagram connections. Remove every <!-- --> block from assembly.xml.`,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// ─── Rule: every routes-to / routes-response-to target must exist ─────────────
|
|
36
|
+
function checkBrokenRoutes(xml, issues) {
|
|
37
|
+
const ids = collectIds(xml);
|
|
38
|
+
for (const m of xml.matchAll(/\broutes-to="([^"]+)"/g)) {
|
|
39
|
+
if (!ids.has(m[1])) {
|
|
40
|
+
issues.push({
|
|
41
|
+
severity: 'ERROR',
|
|
42
|
+
code: 'BROKEN_ROUTES_TO',
|
|
43
|
+
message: `routes-to="${m[1]}" — no element with this id exists in assembly.xml.`,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
for (const m of xml.matchAll(/\broutes-response-to="([^"]+)"/g)) {
|
|
48
|
+
if (!ids.has(m[1])) {
|
|
49
|
+
issues.push({
|
|
50
|
+
severity: 'ERROR',
|
|
51
|
+
code: 'BROKEN_ROUTES_RESPONSE_TO',
|
|
52
|
+
message: `routes-response-to="${m[1]}" — no element with this id exists in assembly.xml.`,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// ─── Rule: vm:// sub-flow endpoints must point to a real cc:local-in ──────────
|
|
58
|
+
// Built-in wcc/* endpoints are exempt.
|
|
59
|
+
function checkLocalOutEndpoints(xml, issues) {
|
|
60
|
+
const ids = collectIds(xml);
|
|
61
|
+
for (const m of xml.matchAll(/endpoint="vm:\/\/([^/]+)\/([^"]+)"/g)) {
|
|
62
|
+
const systemName = m[1];
|
|
63
|
+
const localInId = m[2];
|
|
64
|
+
if (systemName === 'wcc')
|
|
65
|
+
continue; // built-in platform endpoints
|
|
66
|
+
if (!ids.has(localInId)) {
|
|
67
|
+
issues.push({
|
|
68
|
+
severity: 'WARNING',
|
|
69
|
+
code: 'UNRESOLVED_LOCAL_IN',
|
|
70
|
+
message: `vm://${systemName}/${localInId} — no cc:local-in with id="${localInId}" found. Either the local-in is missing or the id is misspelled.`,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// ─── Rule: required attributes per step type ─────────────────────────────────
|
|
76
|
+
function checkRequiredAttributes(xml, issues) {
|
|
77
|
+
for (const tagMatch of xml.matchAll(/<cc:[a-z-]+\b[^>]*(?:\/>|>)/gs)) {
|
|
78
|
+
const tagText = tagMatch[0];
|
|
79
|
+
const nameMatch = tagText.match(/^<(cc:[a-z-]+)/);
|
|
80
|
+
if (!nameMatch)
|
|
81
|
+
continue;
|
|
82
|
+
const tagName = nameMatch[1];
|
|
83
|
+
// workday-out-soap: check application
|
|
84
|
+
if (tagName === 'cc:workday-out-soap') {
|
|
85
|
+
if (!tagText.includes('application=')) {
|
|
86
|
+
issues.push({ severity: 'ERROR', code: 'MISSING_ATTR_APPLICATION', message: `cc:workday-out-soap (id="${extractId(tagText)}") is missing required attribute application= (e.g. Human_Resources).` });
|
|
87
|
+
}
|
|
88
|
+
if (!tagText.includes('version=')) {
|
|
89
|
+
issues.push({ severity: 'ERROR', code: 'MISSING_ATTR_VERSION', message: `cc:workday-out-soap (id="${extractId(tagText)}") is missing required attribute version= (e.g. v46.1).` });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// workday-out-rest: check extra-path
|
|
93
|
+
if (tagName === 'cc:workday-out-rest' && !tagText.includes('extra-path=')) {
|
|
94
|
+
issues.push({ severity: 'ERROR', code: 'MISSING_ATTR_EXTRA_PATH', message: `cc:workday-out-rest (id="${extractId(tagText)}") is missing required attribute extra-path=.` });
|
|
95
|
+
}
|
|
96
|
+
// http-out: check endpoint
|
|
97
|
+
if (tagName === 'cc:http-out' && !tagText.includes('endpoint=')) {
|
|
98
|
+
issues.push({ severity: 'ERROR', code: 'MISSING_ATTR_ENDPOINT', message: `cc:http-out (id="${extractId(tagText)}") is missing required attribute endpoint=.` });
|
|
99
|
+
}
|
|
100
|
+
// xslt-plus: check url
|
|
101
|
+
if (tagName === 'cc:xslt-plus' && !tagText.includes('url=')) {
|
|
102
|
+
issues.push({ severity: 'ERROR', code: 'MISSING_ATTR_URL', message: `cc:xslt-plus (id="${extractId(tagText)}") is missing required attribute url= (path to .xsl file).` });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// ─── Rule: certain elements must be TOP-LEVEL, not inside cc:steps ───────────
|
|
107
|
+
const TOP_LEVEL_ONLY = ['cc:workday-out-rest', 'cc:splitter', 'cc:http-out', 'cc:email-out', 'cc:workday-out-soap'];
|
|
108
|
+
function checkTopLevelOnlyElements(xml, issues) {
|
|
109
|
+
const stepsPattern = /<cc:steps>([\s\S]*?)<\/cc:steps>/g;
|
|
110
|
+
for (const stepsMatch of xml.matchAll(stepsPattern)) {
|
|
111
|
+
const stepsContent = stepsMatch[1];
|
|
112
|
+
for (const tag of TOP_LEVEL_ONLY) {
|
|
113
|
+
if (stepsContent.includes(`<${tag}`)) {
|
|
114
|
+
const stepsIdx = stepsMatch.index;
|
|
115
|
+
const before = xml.substring(0, stepsIdx);
|
|
116
|
+
const asyncMedMatches = [...before.matchAll(/<cc:async-mediation\b[^>]*>/g)];
|
|
117
|
+
const asyncMedMatch = asyncMedMatches[asyncMedMatches.length - 1];
|
|
118
|
+
const containerId = asyncMedMatch ? extractId(asyncMedMatch[0]) : '?';
|
|
119
|
+
issues.push({
|
|
120
|
+
severity: 'ERROR',
|
|
121
|
+
code: 'ELEMENT_INSIDE_STEPS',
|
|
122
|
+
message: `<${tag}> found inside <cc:steps> of "${containerId}". This is a top-level assembly element — it must sit directly inside <cc:assembly>, not inside cc:steps. Move it out of the async-mediation and chain it via routes-to/routes-response-to.`,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// ─── Rule: cc:splitter must NOT have a routes-to attribute ───────────────────
|
|
129
|
+
function checkSplitterRoutes(xml, issues) {
|
|
130
|
+
for (const m of xml.matchAll(/<cc:splitter\b[^>]*>/g)) {
|
|
131
|
+
if (m[0].includes('routes-to=')) {
|
|
132
|
+
issues.push({
|
|
133
|
+
severity: 'ERROR',
|
|
134
|
+
code: 'SPLITTER_HAS_ROUTES_TO',
|
|
135
|
+
message: `cc:splitter (id="${extractId(m[0])}") has a routes-to attribute — the Studio schema does not allow this. Remove routes-to from the splitter. Routing is done via cc:sub-route children only.`,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// ─── Rule: XSL files referenced by url= must exist in WSAR-INF ───────────────
|
|
141
|
+
function checkXslFileReferences(xml, wsDir, issues) {
|
|
142
|
+
for (const m of xml.matchAll(/\burl="([^"]+\.xslt?)"/g)) {
|
|
143
|
+
const xslFile = m[1];
|
|
144
|
+
if (!existsSync(join(wsDir, xslFile))) {
|
|
145
|
+
issues.push({
|
|
146
|
+
severity: 'WARNING',
|
|
147
|
+
code: 'MISSING_XSL_FILE',
|
|
148
|
+
message: `url="${xslFile}" — file not found in WSAR-INF. Create it with create_xsl_transform before testing.`,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// ─── Rule: cc:note is schema-invalid in assembly.xml ─────────────────────────
|
|
154
|
+
function checkCcNote(xml, issues) {
|
|
155
|
+
const matches = [...xml.matchAll(/<cc:note\b/g)];
|
|
156
|
+
if (matches.length > 0) {
|
|
157
|
+
issues.push({
|
|
158
|
+
severity: 'ERROR',
|
|
159
|
+
code: 'CC_NOTE_IN_ASSEMBLY',
|
|
160
|
+
message: `Found ${matches.length} <cc:note> element(s). cc:note is schema-invalid in assembly.xml and crashes Studio if added to assembly-diagram.xml. Replace with an cc:async-mediation that has no routes-to attribute — that is the correct terminal pattern.`,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// ─── Rule: flag remaining TODO stubs ─────────────────────────────────────────
|
|
165
|
+
function checkTodoStubs(xml, issues) {
|
|
166
|
+
const todos = [...xml.matchAll(/id="TODO_([^"]+)"/g)].map(m => m[1]);
|
|
167
|
+
if (todos.length > 0) {
|
|
168
|
+
issues.push({
|
|
169
|
+
severity: 'INFO',
|
|
170
|
+
code: 'TODO_STUBS_REMAINING',
|
|
171
|
+
message: `${todos.length} sub-flow(s) still contain TODO stubs: ${todos.join(', ')}. Fill these in with update_sub_flow before testing.`,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// ─── Diagram drift detection ──────────────────────────────────────────────────
|
|
176
|
+
const RENDERABLE_TAGS = new Set([
|
|
177
|
+
'cc:workday-in', 'cc:local-out', 'cc:local-in', 'cc:async-mediation',
|
|
178
|
+
'cc:route', 'cc:splitter', 'cc:aggregator', 'cc:http-out',
|
|
179
|
+
'cc:workday-out-rest', 'cc:workday-out-soap', 'cc:email-out',
|
|
180
|
+
]);
|
|
181
|
+
export function checkDiagramDrift(assemblyXml, diagramXml) {
|
|
182
|
+
const missing = [];
|
|
183
|
+
for (const m of assemblyXml.matchAll(/<(cc:[a-z-]+)\b[^>]*\bid="([^"]+)"/g)) {
|
|
184
|
+
const tag = m[1];
|
|
185
|
+
const id = m[2];
|
|
186
|
+
if (!RENDERABLE_TAGS.has(tag))
|
|
187
|
+
continue;
|
|
188
|
+
if (!diagramXml.includes(`#${id}`)) {
|
|
189
|
+
missing.push({ tag, id });
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return missing;
|
|
193
|
+
}
|
|
194
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
195
|
+
function collectIds(xml) {
|
|
196
|
+
return new Set([...xml.matchAll(/\bid="([^"]+)"/g)].map(m => m[1]));
|
|
197
|
+
}
|
|
198
|
+
function extractId(tagText) {
|
|
199
|
+
const m = tagText.match(/\bid="([^"]+)"/);
|
|
200
|
+
return m ? m[1] : '?';
|
|
201
|
+
}
|
|
202
|
+
//# sourceMappingURL=assembly-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assembly-validator.js","sourceRoot":"","sources":["../../src/utils/assembly-validator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAa5B,MAAM,UAAU,gBAAgB,CAAC,GAAW,EAAE,QAAuB,IAAI;IACvE,MAAM,MAAM,GAAoB,EAAE,CAAC;IAEnC,kBAAkB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAChC,iBAAiB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC/B,sBAAsB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACpC,uBAAuB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACrC,yBAAyB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACvC,mBAAmB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,KAAK;QAAE,sBAAsB,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IACtD,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACzB,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAE5B,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,iFAAiF;AACjF,8FAA8F;AAE9F,SAAS,kBAAkB,CAAC,GAAW,EAAE,MAAuB;IAC9D,MAAM,OAAO,GAAG,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3C,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,CAAC,IAAI,CAAC;YACV,QAAQ,EAAE,OAAO;YACjB,IAAI,EAAE,sBAAsB;YAC5B,OAAO,EAAE,SAAS,OAAO,CAAC,MAAM,kIAAkI;SACnK,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,iFAAiF;AAEjF,SAAS,iBAAiB,CAAC,GAAW,EAAE,MAAuB;IAC7D,MAAM,GAAG,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAE5B,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,wBAAwB,CAAC,EAAE,CAAC;QACvD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC;YACpB,MAAM,CAAC,IAAI,CAAC;gBACV,QAAQ,EAAE,OAAO;gBACjB,IAAI,EAAE,kBAAkB;gBACxB,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,qDAAqD;aACjF,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,iCAAiC,CAAC,EAAE,CAAC;QAChE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC;YACpB,MAAM,CAAC,IAAI,CAAC;gBACV,QAAQ,EAAE,OAAO;gBACjB,IAAI,EAAE,2BAA2B;gBACjC,OAAO,EAAE,uBAAuB,CAAC,CAAC,CAAC,CAAC,qDAAqD;aAC1F,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC;AAED,iFAAiF;AACjF,uCAAuC;AAEvC,SAAS,sBAAsB,CAAC,GAAW,EAAE,MAAuB;IAClE,MAAM,GAAG,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAE5B,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,qCAAqC,CAAC,EAAE,CAAC;QACpE,MAAM,UAAU,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QACzB,MAAM,SAAS,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QACxB,IAAI,UAAU,KAAK,KAAK;YAAE,SAAS,CAAC,8BAA8B;QAElE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YACxB,MAAM,CAAC,IAAI,CAAC;gBACV,QAAQ,EAAE,SAAS;gBACnB,IAAI,EAAE,qBAAqB;gBAC3B,OAAO,EAAE,QAAQ,UAAU,IAAI,SAAS,8BAA8B,SAAS,kEAAkE;aAClJ,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC;AAED,gFAAgF;AAEhF,SAAS,uBAAuB,CAAC,GAAW,EAAE,MAAuB;IACnE,KAAK,MAAM,QAAQ,IAAI,GAAG,CAAC,QAAQ,CAAC,+BAA+B,CAAC,EAAE,CAAC;QACrE,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAE,CAAC;QAC7B,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;QAClD,IAAI,CAAC,SAAS;YAAE,SAAS;QACzB,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,CAAE,CAAC;QAE9B,sCAAsC;QACtC,IAAI,OAAO,KAAK,qBAAqB,EAAE,CAAC;YACtC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;gBACtC,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,0BAA0B,EAAE,OAAO,EAAE,4BAA4B,SAAS,CAAC,OAAO,CAAC,uEAAuE,EAAE,CAAC,CAAC;YACvM,CAAC;YACD,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;gBAClC,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,sBAAsB,EAAE,OAAO,EAAE,4BAA4B,SAAS,CAAC,OAAO,CAAC,yDAAyD,EAAE,CAAC,CAAC;YACrL,CAAC;QACH,CAAC;QAED,qCAAqC;QACrC,IAAI,OAAO,KAAK,qBAAqB,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;YAC1E,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,yBAAyB,EAAE,OAAO,EAAE,4BAA4B,SAAS,CAAC,OAAO,CAAC,+CAA+C,EAAE,CAAC,CAAC;QAC9K,CAAC;QAED,2BAA2B;QAC3B,IAAI,OAAO,KAAK,aAAa,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YAChE,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,uBAAuB,EAAE,OAAO,EAAE,oBAAoB,SAAS,CAAC,OAAO,CAAC,6CAA6C,EAAE,CAAC,CAAC;QAClK,CAAC;QAED,uBAAuB;QACvB,IAAI,OAAO,KAAK,cAAc,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5D,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,qBAAqB,SAAS,CAAC,OAAO,CAAC,4DAA4D,EAAE,CAAC,CAAC;QAC7K,CAAC;IACH,CAAC;AACH,CAAC;AAED,gFAAgF;AAEhF,MAAM,cAAc,GAAG,CAAC,qBAAqB,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,qBAAqB,CAAC,CAAC;AAEpH,SAAS,yBAAyB,CAAC,GAAW,EAAE,MAAuB;IACrE,MAAM,YAAY,GAAG,mCAAmC,CAAC;IACzD,KAAK,MAAM,UAAU,IAAI,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QACpD,MAAM,YAAY,GAAG,UAAU,CAAC,CAAC,CAAE,CAAC;QACpC,KAAK,MAAM,GAAG,IAAI,cAAc,EAAE,CAAC;YACjC,IAAI,YAAY,CAAC,QAAQ,CAAC,IAAI,GAAG,EAAE,CAAC,EAAE,CAAC;gBACrC,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAM,CAAC;gBACnC,MAAM,MAAM,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;gBAC1C,MAAM,eAAe,GAAG,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,8BAA8B,CAAC,CAAC,CAAC;gBAC7E,MAAM,aAAa,GAAG,eAAe,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;gBAClE,MAAM,WAAW,GAAG,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;gBACvE,MAAM,CAAC,IAAI,CAAC;oBACV,QAAQ,EAAE,OAAO;oBACjB,IAAI,EAAE,sBAAsB;oBAC5B,OAAO,EAAE,IAAI,GAAG,iCAAiC,WAAW,6LAA6L;iBAC1P,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,gFAAgF;AAEhF,SAAS,mBAAmB,CAAC,GAAW,EAAE,MAAuB;IAC/D,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,CAAC;QACtD,IAAI,CAAC,CAAC,CAAC,CAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;YACjC,MAAM,CAAC,IAAI,CAAC;gBACV,QAAQ,EAAE,OAAO;gBACjB,IAAI,EAAE,wBAAwB;gBAC9B,OAAO,EAAE,oBAAoB,SAAS,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,2JAA2J;aACzM,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC;AAED,gFAAgF;AAEhF,SAAS,sBAAsB,CAAC,GAAW,EAAE,KAAa,EAAE,MAAuB;IACjF,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,yBAAyB,CAAC,EAAE,CAAC;QACxD,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QACtB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;YACtC,MAAM,CAAC,IAAI,CAAC;gBACV,QAAQ,EAAE,SAAS;gBACnB,IAAI,EAAE,kBAAkB;gBACxB,OAAO,EAAE,QAAQ,OAAO,qFAAqF;aAC9G,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC;AAED,gFAAgF;AAEhF,SAAS,WAAW,CAAC,GAAW,EAAE,MAAuB;IACvD,MAAM,OAAO,GAAG,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC;IACjD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,CAAC,IAAI,CAAC;YACV,QAAQ,EAAE,OAAO;YACjB,IAAI,EAAE,qBAAqB;YAC3B,OAAO,EAAE,SAAS,OAAO,CAAC,MAAM,kOAAkO;SACnQ,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,gFAAgF;AAEhF,SAAS,cAAc,CAAC,GAAW,EAAE,MAAuB;IAC1D,MAAM,KAAK,GAAG,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC;IACtE,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,CAAC,IAAI,CAAC;YACV,QAAQ,EAAE,MAAM;YAChB,IAAI,EAAE,sBAAsB;YAC5B,OAAO,EAAE,GAAG,KAAK,CAAC,MAAM,0CAA0C,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,sDAAsD;SACzI,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,iFAAiF;AAEjF,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC;IAC9B,eAAe,EAAE,cAAc,EAAE,aAAa,EAAE,oBAAoB;IACpE,UAAU,EAAE,aAAa,EAAE,eAAe,EAAE,aAAa;IACzD,qBAAqB,EAAE,qBAAqB,EAAE,cAAc;CAC7D,CAAC,CAAC;AAEH,MAAM,UAAU,iBAAiB,CAAC,WAAmB,EAAE,UAAkB;IACvE,MAAM,OAAO,GAAuB,EAAE,CAAC;IAEvC,KAAK,MAAM,CAAC,IAAI,WAAW,CAAC,QAAQ,CAAC,qCAAqC,CAAC,EAAE,CAAC;QAC5E,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QAClB,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QACjB,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QACxC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC;YACnC,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,iFAAiF;AAEjF,SAAS,UAAU,CAAC,GAAW;IAC7B,OAAO,IAAI,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC;AACvE,CAAC;AAED,SAAS,SAAS,CAAC,OAAe;IAChC,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAC1C,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,GAAG,CAAC;AACzB,CAAC"}
|
package/dist/utils/fs.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Safe filesystem helpers — path traversal protection.
|
|
2
|
+
* Safe filesystem helpers — path traversal protection + backup.
|
|
3
3
|
*/
|
|
4
4
|
export interface ResolvedPath {
|
|
5
5
|
absolute: string;
|
|
@@ -14,4 +14,9 @@ export declare function resolveSafe(projectName: string, filePath: string): Reso
|
|
|
14
14
|
* Resolve a path directly under the workspace root, rejecting traversal.
|
|
15
15
|
*/
|
|
16
16
|
export declare function resolveWorkspacePath(...parts: string[]): string;
|
|
17
|
+
/**
|
|
18
|
+
* Write a .bak copy of a file next to the original.
|
|
19
|
+
* Returns the backup path, or null if the copy failed (non-fatal).
|
|
20
|
+
*/
|
|
21
|
+
export declare function backupFile(filePath: string): Promise<string | null>;
|
|
17
22
|
//# sourceMappingURL=fs.d.ts.map
|
package/dist/utils/fs.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../src/utils/fs.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../src/utils/fs.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,CAe/E;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAc/D;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAQzE"}
|
package/dist/utils/fs.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Safe filesystem helpers — path traversal protection.
|
|
2
|
+
* Safe filesystem helpers — path traversal protection + backup.
|
|
3
3
|
*/
|
|
4
4
|
import { resolve, join } from 'path';
|
|
5
|
+
import { copyFile } from 'fs/promises';
|
|
5
6
|
import { getConfig } from '../config.js';
|
|
6
7
|
/**
|
|
7
8
|
* Resolve a project-relative file path, rejecting any traversal outside the workspace.
|
|
@@ -32,4 +33,18 @@ export function resolveWorkspacePath(...parts) {
|
|
|
32
33
|
}
|
|
33
34
|
return absolute;
|
|
34
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Write a .bak copy of a file next to the original.
|
|
38
|
+
* Returns the backup path, or null if the copy failed (non-fatal).
|
|
39
|
+
*/
|
|
40
|
+
export async function backupFile(filePath) {
|
|
41
|
+
const backupPath = filePath + '.bak';
|
|
42
|
+
try {
|
|
43
|
+
await copyFile(filePath, backupPath);
|
|
44
|
+
return backupPath;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
35
50
|
//# sourceMappingURL=fs.js.map
|
package/dist/utils/fs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fs.js","sourceRoot":"","sources":["../../src/utils/fs.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAOzC;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,WAAmB,EAAE,QAAgB;IAC/D,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;IACxB,MAAM,aAAa,GAAG,GAAG,CAAC,aAAa,CAAC;IAExC,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,EAAE,QAAQ,CAAC,CAAC;IAErE,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QACxC,MAAM,GAAG,GAAG,IAAI,KAAK,CACnB,6BAA6B,QAAQ,mCAAmC,CAChD,CAAC;QAC3B,GAAG,CAAC,IAAI,GAAG,yBAAyB,CAAC;QACrC,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;AAC1C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAG,KAAe;IACrD,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;IACxB,MAAM,aAAa,GAAG,GAAG,CAAC,aAAa,CAAC;IACxC,MAAM,QAAQ,GAAG,OAAO,CAAC,aAAa,EAAE,GAAG,KAAK,CAAC,CAAC;IAElD,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QACxC,MAAM,GAAG,GAAG,IAAI,KAAK,CACnB,+DAA+D,CACvC,CAAC;QAC3B,GAAG,CAAC,IAAI,GAAG,yBAAyB,CAAC;QACrC,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
1
|
+
{"version":3,"file":"fs.js","sourceRoot":"","sources":["../../src/utils/fs.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAOzC;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,WAAmB,EAAE,QAAgB;IAC/D,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;IACxB,MAAM,aAAa,GAAG,GAAG,CAAC,aAAa,CAAC;IAExC,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,EAAE,QAAQ,CAAC,CAAC;IAErE,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QACxC,MAAM,GAAG,GAAG,IAAI,KAAK,CACnB,6BAA6B,QAAQ,mCAAmC,CAChD,CAAC;QAC3B,GAAG,CAAC,IAAI,GAAG,yBAAyB,CAAC;QACrC,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;AAC1C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAG,KAAe;IACrD,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;IACxB,MAAM,aAAa,GAAG,GAAG,CAAC,aAAa,CAAC;IACxC,MAAM,QAAQ,GAAG,OAAO,CAAC,aAAa,EAAE,GAAG,KAAK,CAAC,CAAC;IAElD,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QACxC,MAAM,GAAG,GAAG,IAAI,KAAK,CACnB,+DAA+D,CACvC,CAAC;QAC3B,GAAG,CAAC,IAAI,GAAG,yBAAyB,CAAC;QACrC,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,QAAgB;IAC/C,MAAM,UAAU,GAAG,QAAQ,GAAG,MAAM,CAAC;IACrC,IAAI,CAAC;QACH,MAAM,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QACrC,OAAO,UAAU,CAAC;IACpB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "workday-studio-mcp-server",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "Enterprise-grade MCP server connecting AI assistants to local Workday Studio / Eclipse workspaces. Runs purely over stdio for local desktop client integration.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|