dlw-machine-setup 0.2.6 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/installer.js +69 -133
- package/package.json +1 -1
package/bin/installer.js
CHANGED
|
@@ -3244,63 +3244,35 @@ var import_fs5 = require("fs");
|
|
|
3244
3244
|
var import_readline = require("readline");
|
|
3245
3245
|
var import_path5 = require("path");
|
|
3246
3246
|
|
|
3247
|
-
// data/wizard-options
|
|
3248
|
-
var
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
};
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
description: "Backend development with SAP Cloud Application Programming model",
|
|
3271
|
-
domains: ["CAP"],
|
|
3272
|
-
mcpServers: ["azure-devops", "context7", "cds-mcp"]
|
|
3273
|
-
},
|
|
3274
|
-
{
|
|
3275
|
-
id: "abap-developer",
|
|
3276
|
-
name: "ABAP Developer",
|
|
3277
|
-
description: "ABAP and SAP backend development",
|
|
3278
|
-
domains: ["ABAP"],
|
|
3279
|
-
mcpServers: ["azure-devops", "context7", "abap", "sap-researcher"]
|
|
3280
|
-
},
|
|
3281
|
-
{
|
|
3282
|
-
id: "btp-developer",
|
|
3283
|
-
name: "BTP Developer",
|
|
3284
|
-
description: "SAP Business Technology Platform development",
|
|
3285
|
-
domains: ["BTP"],
|
|
3286
|
-
mcpServers: ["azure-devops", "context7"]
|
|
3287
|
-
},
|
|
3288
|
-
{
|
|
3289
|
-
id: "sap-dm-developer",
|
|
3290
|
-
name: "SAP Digital Manufacturing Developer",
|
|
3291
|
-
description: "SAP Digital Manufacturing development",
|
|
3292
|
-
domains: ["SAP_DM"],
|
|
3293
|
-
mcpServers: ["azure-devops", "context7"]
|
|
3294
|
-
},
|
|
3295
|
-
{
|
|
3296
|
-
id: "forms-developer",
|
|
3297
|
-
name: "Forms Developer",
|
|
3298
|
-
description: "SAP Forms development",
|
|
3299
|
-
domains: ["FORMS"],
|
|
3300
|
-
mcpServers: ["azure-devops", "context7"]
|
|
3247
|
+
// src/utils/data/fetch-wizard-options.ts
|
|
3248
|
+
var GITHUB_REPO = "DLW-INT-SAP-DEV/DBE_DLWR_AI_WORKSPACE_SETUP_client";
|
|
3249
|
+
async function fetchWizardOptions(token) {
|
|
3250
|
+
try {
|
|
3251
|
+
const headers = {
|
|
3252
|
+
"Accept": "application/vnd.github+json",
|
|
3253
|
+
"Authorization": `Bearer ${token}`
|
|
3254
|
+
};
|
|
3255
|
+
const releaseRes = await fetch(
|
|
3256
|
+
`https://api.github.com/repos/${GITHUB_REPO}/releases/latest`,
|
|
3257
|
+
{ headers }
|
|
3258
|
+
);
|
|
3259
|
+
if (!releaseRes.ok) return null;
|
|
3260
|
+
const release = await releaseRes.json();
|
|
3261
|
+
const asset = release.assets?.find((a) => a.name === "wizard-options.json");
|
|
3262
|
+
if (!asset) return null;
|
|
3263
|
+
const assetRes = await fetch(asset.url, {
|
|
3264
|
+
headers: { ...headers, "Accept": "application/octet-stream" }
|
|
3265
|
+
});
|
|
3266
|
+
if (!assetRes.ok) return null;
|
|
3267
|
+
const data = await assetRes.json();
|
|
3268
|
+
if (!Array.isArray(data.agents) || !Array.isArray(data.personas?.personas)) {
|
|
3269
|
+
return null;
|
|
3301
3270
|
}
|
|
3302
|
-
|
|
3303
|
-
}
|
|
3271
|
+
return data;
|
|
3272
|
+
} catch {
|
|
3273
|
+
return null;
|
|
3274
|
+
}
|
|
3275
|
+
}
|
|
3304
3276
|
|
|
3305
3277
|
// src/utils/data/fetch-contexts.ts
|
|
3306
3278
|
var import_fs2 = require("fs");
|
|
@@ -3463,12 +3435,12 @@ async function getGitHubToken() {
|
|
|
3463
3435
|
}
|
|
3464
3436
|
|
|
3465
3437
|
// src/utils/data/fetch-contexts.ts
|
|
3466
|
-
var
|
|
3438
|
+
var GITHUB_REPO2 = "DLW-INT-SAP-DEV/DBE_DLWR_AI_WORKSPACE_SETUP_client";
|
|
3467
3439
|
var MAX_RETRIES = 3;
|
|
3468
3440
|
var RETRY_DELAY_MS = 2e3;
|
|
3469
3441
|
var MIN_FILE_SIZE = 1024;
|
|
3470
3442
|
async function fetchContexts(options = {}) {
|
|
3471
|
-
const { domains = [], targetDir = process.cwd(), force = false } = options;
|
|
3443
|
+
const { domains = [], targetDir = process.cwd(), force = false, token } = options;
|
|
3472
3444
|
const result = {
|
|
3473
3445
|
successful: [],
|
|
3474
3446
|
failed: [],
|
|
@@ -3479,9 +3451,9 @@ async function fetchContexts(options = {}) {
|
|
|
3479
3451
|
return result;
|
|
3480
3452
|
}
|
|
3481
3453
|
await checkPrerequisites();
|
|
3482
|
-
const githubToken = await getGitHubToken();
|
|
3454
|
+
const githubToken = token ?? await getGitHubToken();
|
|
3483
3455
|
try {
|
|
3484
|
-
const releaseUrl = `https://api.github.com/repos/${
|
|
3456
|
+
const releaseUrl = `https://api.github.com/repos/${GITHUB_REPO2}/releases/latest`;
|
|
3485
3457
|
const headers = {
|
|
3486
3458
|
"Accept": "application/vnd.github+json",
|
|
3487
3459
|
"Authorization": `Bearer ${githubToken}`
|
|
@@ -3656,56 +3628,6 @@ function mergeDirectories(source, target) {
|
|
|
3656
3628
|
// src/utils/setup/setup-mcp.ts
|
|
3657
3629
|
var import_fs3 = require("fs");
|
|
3658
3630
|
var import_path3 = require("path");
|
|
3659
|
-
|
|
3660
|
-
// data/wizard-options/mcp-servers.json
|
|
3661
|
-
var mcp_servers_default = {
|
|
3662
|
-
"azure-devops": {
|
|
3663
|
-
command: "npx",
|
|
3664
|
-
args: ["-y", "@azure-devops/mcp", "__AZURE_ORG__"],
|
|
3665
|
-
description: "Access Azure DevOps work items, boards, pipelines and repositories",
|
|
3666
|
-
useWhen: "User asks about work items, sprints, pipelines, pull requests or Azure DevOps tasks"
|
|
3667
|
-
},
|
|
3668
|
-
context7: {
|
|
3669
|
-
type: "stdio",
|
|
3670
|
-
command: "npx",
|
|
3671
|
-
args: ["-y", "@upstash/context7-mcp"],
|
|
3672
|
-
description: "Fetch up-to-date library and framework documentation",
|
|
3673
|
-
useWhen: "User asks how something works in a specific library or framework (e.g. 'how does X work in SAPUI5?')"
|
|
3674
|
-
},
|
|
3675
|
-
"@ui5/mcp-server": {
|
|
3676
|
-
type: "stdio",
|
|
3677
|
-
command: "npx",
|
|
3678
|
-
args: ["@ui5/mcp-server"],
|
|
3679
|
-
description: "SAPUI5-specific tooling for views, controllers, manifest and OData",
|
|
3680
|
-
useWhen: "User asks to create or modify SAPUI5 views, controllers, fragments or manifest.json"
|
|
3681
|
-
},
|
|
3682
|
-
playwright: {
|
|
3683
|
-
command: "npx",
|
|
3684
|
-
args: ["@playwright/mcp@latest"],
|
|
3685
|
-
description: "Browser automation and end-to-end testing",
|
|
3686
|
-
useWhen: "User asks to write or run browser tests, or automate browser interactions"
|
|
3687
|
-
},
|
|
3688
|
-
"cds-mcp": {
|
|
3689
|
-
command: "npx",
|
|
3690
|
-
args: ["-y", "@cap-js/mcp-server"],
|
|
3691
|
-
description: "SAP CAP/CDS tooling for service definitions, handlers and CQL",
|
|
3692
|
-
useWhen: "User asks about CAP services, CDS models, handlers or CQL queries"
|
|
3693
|
-
},
|
|
3694
|
-
abap: {
|
|
3695
|
-
type: "http",
|
|
3696
|
-
url: "http://localhost:5001/mcp",
|
|
3697
|
-
description: "ABAP development assistant for SAP backend development",
|
|
3698
|
-
useWhen: "User asks about ABAP code, RAP objects, CDS views or SAP backend logic"
|
|
3699
|
-
},
|
|
3700
|
-
"sap-researcher": {
|
|
3701
|
-
command: "npx",
|
|
3702
|
-
args: ["mcp-remote", "http://gsi-em-az1-0057/successormcp/mcp", "--allow-http"],
|
|
3703
|
-
description: "Internal SAP knowledge base and documentation search",
|
|
3704
|
-
useWhen: "User asks about SAP-specific topics, best practices or internal documentation"
|
|
3705
|
-
}
|
|
3706
|
-
};
|
|
3707
|
-
|
|
3708
|
-
// src/utils/setup/setup-mcp.ts
|
|
3709
3631
|
function getAgentMCPTarget(agent) {
|
|
3710
3632
|
switch (agent) {
|
|
3711
3633
|
case "claude-code":
|
|
@@ -3717,7 +3639,6 @@ function getAgentMCPTarget(agent) {
|
|
|
3717
3639
|
return { filePath: ".vscode/mcp.json", rootKey: "servers", dir: ".vscode" };
|
|
3718
3640
|
}
|
|
3719
3641
|
}
|
|
3720
|
-
var ALL_MCP_SERVERS = mcp_servers_default;
|
|
3721
3642
|
async function setupMCPConfiguration(projectPath, mcpConfig, agent) {
|
|
3722
3643
|
const target = getAgentMCPTarget(agent);
|
|
3723
3644
|
const mcpJsonPath = (0, import_path3.join)(projectPath, target.filePath);
|
|
@@ -3743,7 +3664,7 @@ async function setupMCPConfiguration(projectPath, mcpConfig, agent) {
|
|
|
3743
3664
|
if (mergedServers[serverName]) {
|
|
3744
3665
|
skippedServers.push(serverName);
|
|
3745
3666
|
} else {
|
|
3746
|
-
const { description, useWhen, ...mcpFields } = serverConfig;
|
|
3667
|
+
const { description, useWhen, active, ...mcpFields } = serverConfig;
|
|
3747
3668
|
mergedServers[serverName] = mcpFields;
|
|
3748
3669
|
addedServers.push(serverName);
|
|
3749
3670
|
}
|
|
@@ -3752,17 +3673,17 @@ async function setupMCPConfiguration(projectPath, mcpConfig, agent) {
|
|
|
3752
3673
|
(0, import_fs3.writeFileSync)(mcpJsonPath, JSON.stringify(outputFile, null, 2), "utf-8");
|
|
3753
3674
|
return { addedServers, skippedServers };
|
|
3754
3675
|
}
|
|
3755
|
-
function buildMCPConfiguration(selectedItems,
|
|
3676
|
+
function buildMCPConfiguration(selectedItems, baseMcpServers, allMcpServers) {
|
|
3756
3677
|
const config = {};
|
|
3757
|
-
for (const serverName of
|
|
3758
|
-
if (
|
|
3759
|
-
config[serverName] =
|
|
3678
|
+
for (const serverName of baseMcpServers) {
|
|
3679
|
+
if (allMcpServers[serverName]) {
|
|
3680
|
+
config[serverName] = allMcpServers[serverName];
|
|
3760
3681
|
}
|
|
3761
3682
|
}
|
|
3762
3683
|
for (const item of selectedItems) {
|
|
3763
3684
|
for (const serverName of item.mcpServers) {
|
|
3764
|
-
if (
|
|
3765
|
-
config[serverName] =
|
|
3685
|
+
if (allMcpServers[serverName] && !config[serverName]) {
|
|
3686
|
+
config[serverName] = allMcpServers[serverName];
|
|
3766
3687
|
}
|
|
3767
3688
|
}
|
|
3768
3689
|
}
|
|
@@ -3892,9 +3813,21 @@ ${body}`;
|
|
|
3892
3813
|
}
|
|
3893
3814
|
|
|
3894
3815
|
// src/utils/mod.ts
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3816
|
+
async function loadWizardOptions(token) {
|
|
3817
|
+
const remote = await fetchWizardOptions(token);
|
|
3818
|
+
if (!remote) {
|
|
3819
|
+
throw new Error("Failed to load configuration from GitHub release. Check your network and token.");
|
|
3820
|
+
}
|
|
3821
|
+
const filteredMcpServers = Object.fromEntries(
|
|
3822
|
+
Object.entries(remote.mcpServers).filter(([, config]) => config.active !== false)
|
|
3823
|
+
);
|
|
3824
|
+
return {
|
|
3825
|
+
personas: remote.personas.personas.filter((p) => p.active !== false),
|
|
3826
|
+
agents: remote.agents.filter((a) => a.active !== false),
|
|
3827
|
+
baseMcpServers: remote.personas.baseMcpServers,
|
|
3828
|
+
mcpServers: filteredMcpServers
|
|
3829
|
+
};
|
|
3830
|
+
}
|
|
3898
3831
|
|
|
3899
3832
|
// src/index.ts
|
|
3900
3833
|
function getInstructionFilePath(agent) {
|
|
@@ -3938,18 +3871,21 @@ async function main() {
|
|
|
3938
3871
|
console.clear();
|
|
3939
3872
|
console.log("One-Shot Setup Installer\n");
|
|
3940
3873
|
try {
|
|
3941
|
-
const
|
|
3874
|
+
const token = await getGitHubToken();
|
|
3875
|
+
console.log(" Loading configuration...");
|
|
3876
|
+
const options = await loadWizardOptions(token);
|
|
3877
|
+
const config = await collectInputs(options);
|
|
3942
3878
|
if (!config) {
|
|
3943
3879
|
await waitForEnter();
|
|
3944
3880
|
return;
|
|
3945
3881
|
}
|
|
3946
|
-
const proceed = await previewAndConfirm(config);
|
|
3882
|
+
const proceed = await previewAndConfirm(config, options);
|
|
3947
3883
|
if (!proceed) {
|
|
3948
3884
|
console.log("\nNo changes made.");
|
|
3949
3885
|
await waitForEnter();
|
|
3950
3886
|
return;
|
|
3951
3887
|
}
|
|
3952
|
-
const result = await execute(config);
|
|
3888
|
+
const result = await execute(config, token);
|
|
3953
3889
|
printSummary(result);
|
|
3954
3890
|
return;
|
|
3955
3891
|
} catch (error) {
|
|
@@ -3957,22 +3893,22 @@ async function main() {
|
|
|
3957
3893
|
await waitForEnter();
|
|
3958
3894
|
}
|
|
3959
3895
|
}
|
|
3960
|
-
async function collectInputs() {
|
|
3896
|
+
async function collectInputs(options) {
|
|
3961
3897
|
const selectedIds = await esm_default2({
|
|
3962
3898
|
message: "Personas:",
|
|
3963
3899
|
instructions: " Space to select \xB7 Enter to confirm",
|
|
3964
|
-
choices: personas.map((p) => ({
|
|
3900
|
+
choices: options.personas.map((p) => ({
|
|
3965
3901
|
name: p.name.replace(/ Developer$/, ""),
|
|
3966
3902
|
value: p.id
|
|
3967
3903
|
})),
|
|
3968
3904
|
required: true
|
|
3969
3905
|
});
|
|
3970
|
-
const selectedPersonas = personas.filter((p) => selectedIds.includes(p.id));
|
|
3906
|
+
const selectedPersonas = options.personas.filter((p) => selectedIds.includes(p.id));
|
|
3971
3907
|
const agent = await esm_default5({
|
|
3972
3908
|
message: "AI coding tool:",
|
|
3973
|
-
choices: agents
|
|
3909
|
+
choices: options.agents
|
|
3974
3910
|
});
|
|
3975
|
-
const mcpConfig = buildMCPConfiguration(selectedPersonas, baseMcpServers);
|
|
3911
|
+
const mcpConfig = buildMCPConfiguration(selectedPersonas, options.baseMcpServers, options.mcpServers);
|
|
3976
3912
|
let azureDevOpsOrg = "";
|
|
3977
3913
|
if (mcpConfig["azure-devops"]) {
|
|
3978
3914
|
const org = await esm_default4({
|
|
@@ -3999,9 +3935,9 @@ async function collectInputs() {
|
|
|
3999
3935
|
mcpConfig
|
|
4000
3936
|
};
|
|
4001
3937
|
}
|
|
4002
|
-
async function previewAndConfirm(config) {
|
|
3938
|
+
async function previewAndConfirm(config, options) {
|
|
4003
3939
|
const personaNames = config.personas.map((p) => p.name.replace(/ Developer$/, "")).join(", ");
|
|
4004
|
-
const agentDisplay = agents.find((a) => a.value === config.agent)?.name ?? config.agent;
|
|
3940
|
+
const agentDisplay = options.agents.find((a) => a.value === config.agent)?.name ?? config.agent;
|
|
4005
3941
|
const instructionFile = getInstructionFilePath(config.agent);
|
|
4006
3942
|
const mcpConfigFile = getMCPConfigPath(config.agent);
|
|
4007
3943
|
const serverEntries = Object.entries(config.mcpConfig);
|
|
@@ -4029,7 +3965,7 @@ async function previewAndConfirm(config) {
|
|
|
4029
3965
|
console.log("\n" + "\u2500".repeat(48));
|
|
4030
3966
|
return esm_default3({ message: "Proceed?", default: true });
|
|
4031
3967
|
}
|
|
4032
|
-
async function execute(config) {
|
|
3968
|
+
async function execute(config, token) {
|
|
4033
3969
|
const instructionFilePath = getInstructionFilePath(config.agent);
|
|
4034
3970
|
const mcpConfigPath = getMCPConfigPath(config.agent);
|
|
4035
3971
|
const result = {
|
|
@@ -4048,7 +3984,7 @@ async function execute(config) {
|
|
|
4048
3984
|
const domainValues = uniqueDomains.map((d) => d.toLowerCase());
|
|
4049
3985
|
console.log(` Downloading contexts...`);
|
|
4050
3986
|
try {
|
|
4051
|
-
const downloadResult = await fetchContexts({ domains: domainValues });
|
|
3987
|
+
const downloadResult = await fetchContexts({ domains: domainValues, token });
|
|
4052
3988
|
result.domainsInstalled = downloadResult.successful;
|
|
4053
3989
|
result.domainsFailed = downloadResult.failed;
|
|
4054
3990
|
result.failureReasons = downloadResult.failureReasons;
|