d365fo-mcp 1.4.0 → 1.5.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/README.md +8 -7
- package/bridge/D365MetadataBridge/NuGet.config +18 -0
- package/dist/cli/commands/connect.js +1 -1
- package/dist/cli/commands/setup.js +77 -11
- package/dist/cli/context.d.ts +1 -1
- package/dist/cli/context.js +2 -2
- package/dist/cli/mcpJson.js +8 -8
- package/dist/cli/settingsPrompt.js +13 -1
- package/dist/config/settings.js +1 -1
- package/dist/metadata/xmlParser.d.ts +1 -1
- package/dist/metadata/xmlParser.js +4 -3
- package/dist/scripts/build-database.js +1 -1
- package/dist/scripts/build-fts.js +1 -1
- package/dist/scripts/extract-metadata.js +180 -94
- package/dist/server/toolSchemas/d365foFile.js +4 -3
- package/dist/tools/createD365File.d.ts +6 -0
- package/dist/tools/createD365File.js +34 -8
- package/dist/tools/edtExtensionXml.d.ts +28 -0
- package/dist/tools/edtExtensionXml.js +75 -0
- package/dist/tools/generateD365Xml.js +10 -1
- package/dist/tools/xppKnowledge.js +14 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
[](https://www.typescriptlang.org/)
|
|
11
11
|
[](docs/TESTING.md)
|
|
12
12
|
<!-- coverage-badge:start -->
|
|
13
|
-
[](eval/COVERAGE.md) [](eval/COVERAGE.md) [](eval/COVERAGE.md)
|
|
14
14
|
<!-- coverage-badge:end -->
|
|
15
15
|
|
|
16
16
|
*Grounded AI development for Dynamics 365 Finance & Operations — works with GitHub Copilot and Claude Code*
|
|
@@ -74,6 +74,8 @@ Structural violations (wrong order, missing container, disallowed control) **blo
|
|
|
74
74
|
|
|
75
75
|
## Quick Start
|
|
76
76
|
|
|
77
|
+
> **From D365FO platform update 10.0.49 (PU74), Visual Studio 2026 is the supported IDE for X++ development** — Microsoft no longer supports VS 2022. Earlier platform versions still use VS 2022 ≥ 17.14. [Details](https://learn.microsoft.com/en-us/dynamics365/fin-ops-core/fin-ops/get-started/whats-new-platform-updates-10-0-49)
|
|
78
|
+
|
|
77
79
|
**Installing on your own D365FO VM** — the usual case. One line in PowerShell installs Node.js if it is missing, installs the server from npm, and runs the setup wizard, which asks where the index should live and builds the C# bridge for you:
|
|
78
80
|
|
|
79
81
|
```powershell
|
|
@@ -105,7 +107,7 @@ One shared instance for the whole team — the metadata index lives in Blob Stor
|
|
|
105
107
|
|
|
106
108
|
[](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fdynamics365ninja%2Fd365fo-mcp-server%2Frefs%2Fheads%2Fmain%2Finfrastructure%2Fazuredeploy.json)
|
|
107
109
|
|
|
108
|
-
Deployment guide: [docs/SETUP_AZURE.md](docs/SETUP_AZURE.md)
|
|
110
|
+
Deployment guide: [docs/SETUP_AZURE.md](docs/SETUP_AZURE.md) — includes CI/CD pipeline automation
|
|
109
111
|
|
|
110
112
|
---
|
|
111
113
|
|
|
@@ -114,11 +116,10 @@ Deployment guide: [docs/SETUP_AZURE.md](docs/SETUP_AZURE.md) · CI/CD automation
|
|
|
114
116
|
| Getting started | Reference | Operations |
|
|
115
117
|
|-----------------|-----------|------------|
|
|
116
118
|
| [Quick Start](docs/QUICK_START.md) — connect or install | [All 26 tools](docs/MCP_TOOLS.md) | [Azure deployment](docs/SETUP_AZURE.md) |
|
|
117
|
-
| [Setup scenarios A–F](docs/SETUP.md) | [`.mcp.json` reference](docs/MCP_CONFIG.md) | [DevOps pipelines](docs/
|
|
118
|
-
| [Claude Code setup](docs/
|
|
119
|
-
| [Usage examples](docs/USAGE_EXAMPLES.md) — real tool chains | [
|
|
120
|
-
| | [
|
|
121
|
-
| | [Backlog](docs/BACKLOG.md) — deferred work & ideas | [Coverage](eval/COVERAGE.md) — what the badge counts |
|
|
119
|
+
| [Setup scenarios A–F](docs/SETUP.md) | [`.mcp.json` reference](docs/MCP_CONFIG.md) | [DevOps pipelines](docs/SETUP_AZURE.md#azure-devops-pipelines) |
|
|
120
|
+
| [Claude Code setup](docs/SETUP.md#claude-code-cli) | [Configuration](docs/CONFIGURATION.md) | [Testing](docs/TESTING.md) |
|
|
121
|
+
| [Usage examples](docs/USAGE_EXAMPLES.md) — real tool chains | [Architecture](docs/ARCHITECTURE.md) | [Custom / ISV models](docs/CUSTOM_EXTENSIONS.md) |
|
|
122
|
+
| | | [Coverage](eval/COVERAGE.md) — what the badge counts |
|
|
122
123
|
|
|
123
124
|
## License
|
|
124
125
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<!--
|
|
3
|
+
D365FO dev VMs frequently ship a machine-wide NuGet.config that only lists
|
|
4
|
+
offline/VS package sources (e.g. "C:\Program Files\dotnet\library-packs" and
|
|
5
|
+
"Microsoft Visual Studio Offline Packages") — nuget.org isn't in it, so
|
|
6
|
+
restoring System.Text.Json / Microsoft.NETFramework.ReferenceAssemblies.net48
|
|
7
|
+
fails with NU1101 even though the machine has internet access.
|
|
8
|
+
|
|
9
|
+
This file has no <clear/>, so NuGet MERGES it with whatever the machine/user
|
|
10
|
+
config already defines — it only adds nuget.org, it never removes the
|
|
11
|
+
offline sources the D365FO tooling relies on. See docs/SETUP.md
|
|
12
|
+
"Restrictive NuGet feed".
|
|
13
|
+
-->
|
|
14
|
+
<configuration>
|
|
15
|
+
<packageSources>
|
|
16
|
+
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
|
|
17
|
+
</packageSources>
|
|
18
|
+
</configuration>
|
|
@@ -104,7 +104,7 @@ function serverEntry(url, apiKey, alwaysLoad) {
|
|
|
104
104
|
url,
|
|
105
105
|
...(apiKey ? { headers: { 'X-Api-Key': apiKey } } : {}),
|
|
106
106
|
// Without it Claude Code defers the tools and may answer X++ questions from
|
|
107
|
-
// built-in search instead (docs/
|
|
107
|
+
// built-in search instead (docs/SETUP.md § Claude Code CLI).
|
|
108
108
|
...(alwaysLoad ? { alwaysLoad: true } : {}),
|
|
109
109
|
};
|
|
110
110
|
}
|
|
@@ -153,7 +153,7 @@ function openRootStore() {
|
|
|
153
153
|
}
|
|
154
154
|
/** D365FO environment: type, then the paths/models that type needs. */
|
|
155
155
|
async function configureEnvironment(store, scenario) {
|
|
156
|
-
p.log.step('D365FO environment
|
|
156
|
+
p.log.step('D365FO environment');
|
|
157
157
|
let envType;
|
|
158
158
|
if (scenario === 'ude') {
|
|
159
159
|
envType = 'ude';
|
|
@@ -193,29 +193,90 @@ async function configureEnvironment(store, scenario) {
|
|
|
193
193
|
}
|
|
194
194
|
/** Model/paths the write tools target. Auto-detection covers what is left empty. */
|
|
195
195
|
async function configureWorkspace(store, scenario) {
|
|
196
|
-
p.log.step('Workspace
|
|
196
|
+
p.log.step('Workspace target');
|
|
197
197
|
await askSetting(store, setting('workspace.modelName'));
|
|
198
198
|
await askSetting(store, setting('workspace.path'), { required: scenario === 'hybrid' || scenario === 'ude' });
|
|
199
199
|
await askSetting(store, setting('workspace.solutionsPath'));
|
|
200
200
|
}
|
|
201
201
|
async function configureNaming(store) {
|
|
202
|
-
p.log.step('Naming
|
|
202
|
+
p.log.step('Naming');
|
|
203
203
|
await askSettings(store, settingsInSection('naming', 'basic'));
|
|
204
204
|
}
|
|
205
205
|
async function configureIndex(store) {
|
|
206
|
-
p.log.step('Metadata index
|
|
206
|
+
p.log.step('Metadata index');
|
|
207
207
|
await askSetting(store, setting('index.extractMode'));
|
|
208
208
|
const includeLabels = await askSetting(store, setting('index.includeLabels'));
|
|
209
209
|
if (includeLabels)
|
|
210
210
|
await askSetting(store, setting('index.labelLanguages'));
|
|
211
211
|
}
|
|
212
212
|
async function maybeBuildIndex() {
|
|
213
|
-
if (!await askConfirm('Build the metadata index now? (custom
|
|
213
|
+
if (!await askConfirm('Build the metadata index now? (custom: minutes, full: 1-2 h)')) {
|
|
214
214
|
p.log.warn('Skipped — run `d365fo-mcp index` before first use.');
|
|
215
215
|
return true;
|
|
216
216
|
}
|
|
217
217
|
return rebuildIndex(rootTarget());
|
|
218
218
|
}
|
|
219
|
+
function writeCopilotSetupReadme(stageDir, includeLocalMcpCopy) {
|
|
220
|
+
const readmePath = resolve(stageDir, 'README.md');
|
|
221
|
+
const lines = [
|
|
222
|
+
'# VS setup quick guide',
|
|
223
|
+
'',
|
|
224
|
+
'This folder is generated by `d365fo-mcp setup` to simplify Visual Studio onboarding.',
|
|
225
|
+
'',
|
|
226
|
+
'1. Copy .mcp.json',
|
|
227
|
+
' - Recommended (all solutions): %USERPROFILE%\\.mcp.json',
|
|
228
|
+
' - Per solution: place .mcp.json next to your .sln file',
|
|
229
|
+
includeLocalMcpCopy
|
|
230
|
+
? ' - Local copy prepared here: .mcp.json'
|
|
231
|
+
: ` - Local copy path: ${paths.mcpSuggestion}`,
|
|
232
|
+
'',
|
|
233
|
+
'2. Copy .github/copilot-instructions.md',
|
|
234
|
+
' - Destination: a parent folder of your solution directories',
|
|
235
|
+
' - Why: provides mandatory D365FO tool-routing and safety rules for Copilot',
|
|
236
|
+
'',
|
|
237
|
+
'3. Restart Visual Studio after copying files.',
|
|
238
|
+
];
|
|
239
|
+
fs.writeFileSync(readmePath, lines.join('\n') + '\n', 'utf8');
|
|
240
|
+
}
|
|
241
|
+
async function maybePrepareCopilotInstructions(store) {
|
|
242
|
+
const source = resolve(repoRoot, '.github', 'copilot-instructions.md');
|
|
243
|
+
if (!fs.existsSync(source)) {
|
|
244
|
+
p.log.warn('Cannot find .github\\copilot-instructions.md in the package; skipping copy helper.');
|
|
245
|
+
return {};
|
|
246
|
+
}
|
|
247
|
+
const wantsDirectCopy = await askConfirm('Create/copy .github/copilot-instructions.md into the solutions folder now?', true);
|
|
248
|
+
const solutionsPath = String(readSetting(store, setting('workspace.solutionsPath')) ?? '').trim();
|
|
249
|
+
if (wantsDirectCopy && solutionsPath) {
|
|
250
|
+
const targetDir = resolve(solutionsPath, '.github');
|
|
251
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
252
|
+
fs.copyFileSync(source, resolve(targetDir, 'copilot-instructions.md'));
|
|
253
|
+
p.log.success(`Prepared: ${resolve(targetDir, 'copilot-instructions.md')}`);
|
|
254
|
+
return {};
|
|
255
|
+
}
|
|
256
|
+
const stageDir = resolve(dataRoot(), 'copilot-setup');
|
|
257
|
+
const stageGitHubDir = resolve(stageDir, '.github');
|
|
258
|
+
fs.mkdirSync(stageGitHubDir, { recursive: true });
|
|
259
|
+
fs.copyFileSync(source, resolve(stageGitHubDir, 'copilot-instructions.md'));
|
|
260
|
+
writeCopilotSetupReadme(stageDir, false);
|
|
261
|
+
if (wantsDirectCopy && !solutionsPath) {
|
|
262
|
+
p.log.warn('Solutions folder is empty, so files were prepared in the local staging folder instead.');
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
p.log.info('Copy was skipped; files were prepared in a local staging folder for later use.');
|
|
266
|
+
}
|
|
267
|
+
p.log.info(`Staging folder: ${stageDir}`);
|
|
268
|
+
return { stagingDir: stageDir };
|
|
269
|
+
}
|
|
270
|
+
function finalizeStagedCopilotFiles(plan) {
|
|
271
|
+
if (!plan.stagingDir)
|
|
272
|
+
return;
|
|
273
|
+
const localMcp = paths.mcpSuggestion;
|
|
274
|
+
if (fs.existsSync(localMcp)) {
|
|
275
|
+
fs.copyFileSync(localMcp, resolve(plan.stagingDir, '.mcp.json'));
|
|
276
|
+
writeCopilotSetupReadme(plan.stagingDir, true);
|
|
277
|
+
p.log.success(`Prepared: ${resolve(plan.stagingDir, '.mcp.json')}`);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
219
280
|
export function savedNote(store) {
|
|
220
281
|
const rel = relative(dataRoot(), store.configPath) || store.configPath;
|
|
221
282
|
const lines = [`Settings written to ${rel}`];
|
|
@@ -237,12 +298,12 @@ export async function setupCommand() {
|
|
|
237
298
|
p.log.warn(`This is d365fo-mcp ${release.current}; ${release.latest} is published.\n` +
|
|
238
299
|
` Updating first avoids rebuilding the index twice: ${installMode === 'npm' ? 'npm install -g d365fo-mcp@latest' : 'd365fo-mcp update'}`);
|
|
239
300
|
}
|
|
240
|
-
const scenario = await askSelect('How will this
|
|
241
|
-
{ value: 'local-stdio', label: 'E — Local stdio ★', hint: '
|
|
242
|
-
{ value: 'hybrid', label: 'B — Hybrid ★', hint: 'Azure serves
|
|
243
|
-
{ value: 'local-http', label: 'C — Local HTTP', hint: '
|
|
244
|
-
{ value: 'ude', label: 'D — UDE', hint: 'Unified Developer Experience
|
|
245
|
-
{ value: 'multi', label: 'F — Multi-instance', hint: '
|
|
301
|
+
const scenario = await askSelect('How will this machine use MCP? (docs/SETUP.md)', [
|
|
302
|
+
{ value: 'local-stdio', label: 'E — Local stdio ★', hint: 'Single developer VM. Visual Studio launches MCP.' },
|
|
303
|
+
{ value: 'hybrid', label: 'B — Hybrid ★', hint: 'Azure serves search. Local companion handles writes.' },
|
|
304
|
+
{ value: 'local-http', label: 'C — Local HTTP', hint: 'Multiple local clients share one MCP HTTP port.' },
|
|
305
|
+
{ value: 'ude', label: 'D — UDE', hint: 'Unified Developer Experience setup.' },
|
|
306
|
+
{ value: 'multi', label: 'F — Multi-instance', hint: 'One machine, multiple isolated D365FO instances.' },
|
|
246
307
|
]);
|
|
247
308
|
// Before anything is written: every path below hangs off the data directory.
|
|
248
309
|
await configureDataRoot();
|
|
@@ -271,6 +332,7 @@ export async function setupCommand() {
|
|
|
271
332
|
const url = await askText({ message: 'Azure server URL', placeholder: 'https://your-server.azurewebsites.net/mcp/', required: true });
|
|
272
333
|
await configureEnvironment(store, scenario);
|
|
273
334
|
await configureWorkspace(store, scenario);
|
|
335
|
+
const copilotPlan = await maybePrepareCopilotInstructions(store);
|
|
274
336
|
await configureNaming(store);
|
|
275
337
|
await askSecrets(store, ['behavior']);
|
|
276
338
|
await askAdvanced(store, ['environment', 'workspace', 'naming', 'bridge', 'behavior', 'server']);
|
|
@@ -280,6 +342,7 @@ export async function setupCommand() {
|
|
|
280
342
|
'd365fo-azure': { url },
|
|
281
343
|
'd365fo-local': stdioServer(store),
|
|
282
344
|
});
|
|
345
|
+
finalizeStagedCopilotFiles(copilotPlan);
|
|
283
346
|
placementNote();
|
|
284
347
|
p.outro('Hybrid setup complete — no local index needed (Azure serves the search).');
|
|
285
348
|
return;
|
|
@@ -288,6 +351,7 @@ export async function setupCommand() {
|
|
|
288
351
|
writeSetting(store, setting('server.mode'), 'full');
|
|
289
352
|
await configureEnvironment(store, scenario);
|
|
290
353
|
await configureWorkspace(store, scenario);
|
|
354
|
+
const copilotPlan = await maybePrepareCopilotInstructions(store);
|
|
291
355
|
await configureNaming(store);
|
|
292
356
|
await configureIndex(store);
|
|
293
357
|
let port = Number(readSetting(store, setting('server.port')) ?? 8080);
|
|
@@ -305,6 +369,7 @@ export async function setupCommand() {
|
|
|
305
369
|
}
|
|
306
370
|
if (scenario === 'local-http') {
|
|
307
371
|
mcpJsonNote({ 'd365fo-mcp-tools': { url: `http://localhost:${port}/mcp/` } });
|
|
372
|
+
finalizeStagedCopilotFiles(copilotPlan);
|
|
308
373
|
placementNote();
|
|
309
374
|
p.outro('Done. Start the server with: d365fo-mcp start');
|
|
310
375
|
return;
|
|
@@ -312,6 +377,7 @@ export async function setupCommand() {
|
|
|
312
377
|
// D / E — the IDE spawns dist/index.js itself and is pointed at the config
|
|
313
378
|
// file; every other setting comes from there.
|
|
314
379
|
mcpJsonNote({ 'd365fo-mcp-tools': stdioServer(store) });
|
|
380
|
+
finalizeStagedCopilotFiles(copilotPlan);
|
|
315
381
|
placementNote();
|
|
316
382
|
p.outro('Done. VS spawns the server automatically — no manual start needed.');
|
|
317
383
|
}
|
package/dist/cli/context.d.ts
CHANGED
|
@@ -60,7 +60,7 @@ export declare const paths: {
|
|
|
60
60
|
readonly instancesDir: string;
|
|
61
61
|
readonly defaultDb: string;
|
|
62
62
|
readonly defaultLabelsDb: string;
|
|
63
|
-
/** Where
|
|
63
|
+
/** Where setup writes the ready-to-copy .mcp.json file. */
|
|
64
64
|
readonly mcpSuggestion: string;
|
|
65
65
|
/**
|
|
66
66
|
* Where `dotnet build` puts the bridge.
|
package/dist/cli/context.js
CHANGED
|
@@ -120,8 +120,8 @@ export const paths = {
|
|
|
120
120
|
get instancesDir() { return resolve(currentDataRoot, 'instances'); },
|
|
121
121
|
get defaultDb() { return resolve(currentDataRoot, 'data', 'xpp-metadata.db'); },
|
|
122
122
|
get defaultLabelsDb() { return resolve(currentDataRoot, 'data', 'xpp-metadata-labels.db'); },
|
|
123
|
-
/** Where
|
|
124
|
-
get mcpSuggestion() { return resolve(currentDataRoot, 'mcp
|
|
123
|
+
/** Where setup writes the ready-to-copy .mcp.json file. */
|
|
124
|
+
get mcpSuggestion() { return resolve(currentDataRoot, '.mcp.json'); },
|
|
125
125
|
/**
|
|
126
126
|
* Where `dotnet build` puts the bridge.
|
|
127
127
|
*
|
package/dist/cli/mcpJson.js
CHANGED
|
@@ -28,20 +28,20 @@ export function stdioServer(store, extraEnv) {
|
|
|
28
28
|
export function mcpJsonNote(servers, title = '.mcp.json') {
|
|
29
29
|
const json = JSON.stringify({ servers }, null, 2);
|
|
30
30
|
p.note(json, title);
|
|
31
|
-
// Also write the
|
|
32
|
-
//
|
|
33
|
-
//
|
|
31
|
+
// Also write the JSON to a file so it can be copied as-is into VS.
|
|
32
|
+
// It goes to the data directory, not the package: npm updates replace the
|
|
33
|
+
// package directory and may not be writable.
|
|
34
34
|
const outPath = paths.mcpSuggestion;
|
|
35
35
|
fs.mkdirSync(dirname(outPath), { recursive: true });
|
|
36
36
|
fs.writeFileSync(outPath, json + '\n', 'utf8');
|
|
37
|
-
p.log.info(
|
|
37
|
+
p.log.info(`.mcp.json prepared at: ${outPath}`);
|
|
38
38
|
}
|
|
39
39
|
export function placementNote() {
|
|
40
|
-
p.note('
|
|
40
|
+
p.note('Copy the generated .mcp.json to one of these locations:\n' +
|
|
41
41
|
' %USERPROFILE%\\.mcp.json — all solutions (recommended)\n' +
|
|
42
42
|
' next to the .sln — that solution only\n\n' +
|
|
43
|
-
'
|
|
44
|
-
'
|
|
45
|
-
'Restart Visual Studio after
|
|
43
|
+
'Make sure .github\\copilot-instructions.md exists in a parent folder\n' +
|
|
44
|
+
'of your solutions (mandatory for Copilot — see docs/SETUP.md).\n' +
|
|
45
|
+
'Restart Visual Studio after copying .mcp.json.', 'Where it goes');
|
|
46
46
|
}
|
|
47
47
|
//# sourceMappingURL=mcpJson.js.map
|
|
@@ -14,7 +14,19 @@ import { askConfirm, askSelect, askText, ensure, p } from './ui.js';
|
|
|
14
14
|
/** "Label\n description" — the uniform question layout. */
|
|
15
15
|
function message(setting, suffix) {
|
|
16
16
|
const head = suffix ? `${setting.label} ${suffix}` : setting.label;
|
|
17
|
-
|
|
17
|
+
if (setting.path === 'environment.type')
|
|
18
|
+
return head;
|
|
19
|
+
return `${head}\n${c.dim(compactDescription(setting.description))}`;
|
|
20
|
+
}
|
|
21
|
+
function compactDescription(text) {
|
|
22
|
+
const normalized = text.replace(/\s+/g, ' ').trim();
|
|
23
|
+
const primary = normalized.split(/(?<=[.!?])\s+/)[0] ?? normalized;
|
|
24
|
+
const wrapped = wrapText(primary, 76, ' ').split('\n');
|
|
25
|
+
if (wrapped.length <= 2)
|
|
26
|
+
return wrapped.join('\n');
|
|
27
|
+
const lines = wrapped.slice(0, 2);
|
|
28
|
+
lines[1] = `${lines[1].replace(/\.*\s*$/, '')}...`;
|
|
29
|
+
return lines.join('\n');
|
|
18
30
|
}
|
|
19
31
|
function wrapText(text, width, indent) {
|
|
20
32
|
const words = text.split(/\s+/);
|
package/dist/config/settings.js
CHANGED
|
@@ -80,7 +80,7 @@ export const SETTINGS = [
|
|
|
80
80
|
tier: 'basic',
|
|
81
81
|
type: 'path',
|
|
82
82
|
label: 'Packages root (PackagesLocalDirectory)',
|
|
83
|
-
description: '
|
|
83
|
+
description: 'AOT packages folder (PackagesLocalDirectory) used as the read-only source for indexing. ' +
|
|
84
84
|
'Machine-wide on a traditional VM; UDE resolves it from the XPP config instead.',
|
|
85
85
|
placeholder: 'C:\\AOSService\\PackagesLocalDirectory',
|
|
86
86
|
},
|
|
@@ -48,8 +48,8 @@ export interface XppClassExtensionRecord extends XppExtensionMembers {
|
|
|
48
48
|
*/
|
|
49
49
|
export declare function buildClassExtensionRecord(classInfo: XppClassInfo, model: string): XppClassExtensionRecord | null;
|
|
50
50
|
export declare class XppMetadataParser {
|
|
51
|
-
private parser;
|
|
52
51
|
private enhancedParser;
|
|
52
|
+
private get parser();
|
|
53
53
|
constructor();
|
|
54
54
|
/**
|
|
55
55
|
* Parse an X++ class file (AxClass XML)
|
|
@@ -57,14 +57,15 @@ export function buildClassExtensionRecord(classInfo, model) {
|
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
59
|
export class XppMetadataParser {
|
|
60
|
-
parser;
|
|
61
60
|
enhancedParser;
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
get parser() {
|
|
62
|
+
return new Parser({
|
|
64
63
|
explicitArray: false,
|
|
65
64
|
mergeAttrs: true,
|
|
66
65
|
trim: true,
|
|
67
66
|
});
|
|
67
|
+
}
|
|
68
|
+
constructor() {
|
|
68
69
|
this.enhancedParser = new EnhancedXppParser();
|
|
69
70
|
}
|
|
70
71
|
/**
|
|
@@ -31,7 +31,7 @@ var SETTINGS = [
|
|
|
31
31
|
tier: "basic",
|
|
32
32
|
type: "path",
|
|
33
33
|
label: "Packages root (PackagesLocalDirectory)",
|
|
34
|
-
description: "
|
|
34
|
+
description: "AOT packages folder (PackagesLocalDirectory) used as the read-only source for indexing. Machine-wide on a traditional VM; UDE resolves it from the XPP config instead.",
|
|
35
35
|
placeholder: "C:\\AOSService\\PackagesLocalDirectory"
|
|
36
36
|
},
|
|
37
37
|
{
|
|
@@ -31,7 +31,7 @@ var SETTINGS = [
|
|
|
31
31
|
tier: "basic",
|
|
32
32
|
type: "path",
|
|
33
33
|
label: "Packages root (PackagesLocalDirectory)",
|
|
34
|
-
description: "
|
|
34
|
+
description: "AOT packages folder (PackagesLocalDirectory) used as the read-only source for indexing. Machine-wide on a traditional VM; UDE resolves it from the XPP config instead.",
|
|
35
35
|
placeholder: "C:\\AOSService\\PackagesLocalDirectory"
|
|
36
36
|
},
|
|
37
37
|
{
|