@linkup-ai/abap-ai 0.1.0
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 +389 -0
- package/dist/adt-client.js +383 -0
- package/dist/cli/activate.js +127 -0
- package/dist/cli/init.js +559 -0
- package/dist/cli/link.js +148 -0
- package/dist/cli/remove.js +83 -0
- package/dist/cli/status.js +231 -0
- package/dist/cli/systems.js +72 -0
- package/dist/cli.js +92 -0
- package/dist/index.js +1442 -0
- package/dist/knowledge/abap/abap-dictionary.md +199 -0
- package/dist/knowledge/abap/abap-sql.md +296 -0
- package/dist/knowledge/abap/amdp.md +273 -0
- package/dist/knowledge/abap/clean-code.md +293 -0
- package/dist/knowledge/abap/cloud-background-processing.md +250 -0
- package/dist/knowledge/abap/cloud-communication.md +265 -0
- package/dist/knowledge/abap/cloud-development.md +176 -0
- package/dist/knowledge/abap/cloud-extensibility.md +252 -0
- package/dist/knowledge/abap/cloud-released-apis.md +261 -0
- package/dist/knowledge/abap/constructor-expressions.md +289 -0
- package/dist/knowledge/abap/enhancements.md +232 -0
- package/dist/knowledge/abap/exceptions.md +271 -0
- package/dist/knowledge/abap/internal-tables.md +205 -0
- package/dist/knowledge/abap/object-orientation.md +298 -0
- package/dist/knowledge/abap/performance.md +216 -0
- package/dist/knowledge/abap/rap-abstract-entities.md +206 -0
- package/dist/knowledge/abap/rap-business-events.md +216 -0
- package/dist/knowledge/abap/rap-draft.md +191 -0
- package/dist/knowledge/abap/rap-eml.md +453 -0
- package/dist/knowledge/abap/rap-end-to-end.md +486 -0
- package/dist/knowledge/abap/rap-feature-control.md +185 -0
- package/dist/knowledge/abap/rap-numbering.md +280 -0
- package/dist/knowledge/abap/rap-service-exposure.md +163 -0
- package/dist/knowledge/abap/rap-unmanaged.md +468 -0
- package/dist/knowledge/abap/string-processing.md +180 -0
- package/dist/knowledge/abap/unit-testing.md +303 -0
- package/dist/knowledge/abap-cds/access-control.md +241 -0
- package/dist/knowledge/abap-cds/annotations.md +331 -0
- package/dist/knowledge/abap-cds/associations.md +254 -0
- package/dist/knowledge/abap-cds/expressions.md +230 -0
- package/dist/knowledge/abap-cds/functions.md +245 -0
- package/dist/knowledge/abap-cds/metadata-extensions.md +294 -0
- package/dist/knowledge/cap/authentication.md +278 -0
- package/dist/knowledge/cap/cdl-syntax.md +247 -0
- package/dist/knowledge/cap/cql-queries.md +266 -0
- package/dist/knowledge/cap/deployment.md +343 -0
- package/dist/knowledge/cap/event-handlers.md +287 -0
- package/dist/knowledge/cap/fiori-integration.md +303 -0
- package/dist/knowledge/cap/service-definitions.md +287 -0
- package/dist/knowledge/fiori/annotations.md +347 -0
- package/dist/knowledge/fiori/deployment.md +340 -0
- package/dist/knowledge/fiori/fiori-elements.md +332 -0
- package/dist/knowledge/fiori/fiori-side-effects.md +107 -0
- package/dist/knowledge/fiori/fiori-valuelist.md +144 -0
- package/dist/knowledge/fiori/ui5-controllers.md +358 -0
- package/dist/knowledge/fiori/ui5-data-binding.md +311 -0
- package/dist/knowledge/fiori/ui5-fragments-dialogs.md +330 -0
- package/dist/knowledge/fiori/ui5-manifest.md +411 -0
- package/dist/knowledge/fiori/ui5-routing.md +303 -0
- package/dist/knowledge/fiori/ui5-xml-views.md +294 -0
- package/dist/license-guard.js +81 -0
- package/dist/logger.js +114 -0
- package/dist/postinstall.js +165 -0
- package/dist/security-audit.js +136 -0
- package/dist/security-policy.js +322 -0
- package/dist/system-profile.js +207 -0
- package/dist/tools/abap-doc.js +72 -0
- package/dist/tools/abapgit.js +161 -0
- package/dist/tools/activate.js +71 -0
- package/dist/tools/atc-check.js +117 -0
- package/dist/tools/auth-object.js +56 -0
- package/dist/tools/breakpoints.js +76 -0
- package/dist/tools/call-hierarchy.js +84 -0
- package/dist/tools/cds-annotations.js +98 -0
- package/dist/tools/cds-dependencies.js +65 -0
- package/dist/tools/check.js +47 -0
- package/dist/tools/code-completion.js +70 -0
- package/dist/tools/code-coverage.js +111 -0
- package/dist/tools/create-amdp.js +111 -0
- package/dist/tools/create-dcl.js +81 -0
- package/dist/tools/create-transport.js +38 -0
- package/dist/tools/create.js +285 -0
- package/dist/tools/data-preview.js +37 -0
- package/dist/tools/delete.js +45 -0
- package/dist/tools/deploy-bsp.js +298 -0
- package/dist/tools/discovery.js +59 -0
- package/dist/tools/element-info.js +93 -0
- package/dist/tools/enhancements.js +186 -0
- package/dist/tools/extract-method.js +44 -0
- package/dist/tools/function-group.js +59 -0
- package/dist/tools/knowledge.js +275 -0
- package/dist/tools/lock-object.js +75 -0
- package/dist/tools/message-class.js +67 -0
- package/dist/tools/navigate.js +80 -0
- package/dist/tools/number-range.js +57 -0
- package/dist/tools/object-documentation.js +43 -0
- package/dist/tools/object-structure.js +78 -0
- package/dist/tools/object-versions.js +57 -0
- package/dist/tools/package-contents.js +60 -0
- package/dist/tools/pretty-printer.js +35 -0
- package/dist/tools/publish-binding.js +49 -0
- package/dist/tools/quick-fix.js +69 -0
- package/dist/tools/read.js +172 -0
- package/dist/tools/refactor-rename.js +60 -0
- package/dist/tools/release-transport.js +24 -0
- package/dist/tools/released-apis.js +51 -0
- package/dist/tools/repository-tree.js +90 -0
- package/dist/tools/scaffold-rap.js +642 -0
- package/dist/tools/search.js +73 -0
- package/dist/tools/shared/data-format.js +101 -0
- package/dist/tools/sql-console.js +17 -0
- package/dist/tools/system-info.js +271 -0
- package/dist/tools/traces.js +66 -0
- package/dist/tools/transport-contents.js +83 -0
- package/dist/tools/transports.js +68 -0
- package/dist/tools/unit-test.js +135 -0
- package/dist/tools/where-used.js +59 -0
- package/dist/tools/write.js +120 -0
- package/package.json +50 -0
package/dist/cli/link.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.link = link;
|
|
40
|
+
const prompts_1 = __importDefault(require("prompts"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const init_js_1 = require("./init.js");
|
|
43
|
+
const LOCAL_MCP_PATH = path.join(process.cwd(), ".mcp.json");
|
|
44
|
+
async function link() {
|
|
45
|
+
console.log(`
|
|
46
|
+
╭─────────────────────────────────────╮
|
|
47
|
+
│ LKPABAP.ai — Link Workspace │
|
|
48
|
+
│ Conecta este projeto ao SAP │
|
|
49
|
+
╰─────────────────────────────────────╯
|
|
50
|
+
|
|
51
|
+
Workspace: ${process.cwd()}
|
|
52
|
+
`);
|
|
53
|
+
// Lê config global
|
|
54
|
+
const globalConfig = (0, init_js_1.readMcpConfig)(init_js_1.GLOBAL_MCP_PATH);
|
|
55
|
+
const sapEntries = Object.entries(globalConfig.mcpServers).filter(([k]) => k.startsWith("abap-"));
|
|
56
|
+
if (sapEntries.length === 0) {
|
|
57
|
+
console.log(" ✗ Nenhum sistema SAP encontrado na configuração global.\n" +
|
|
58
|
+
" Execute primeiro: abap-ai init\n");
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
// Monta opções para seleção
|
|
62
|
+
const choices = sapEntries.map(([name, server]) => {
|
|
63
|
+
const env = server.env || {};
|
|
64
|
+
const url = env.SAP_URL || "?";
|
|
65
|
+
const client = env.SAP_CLIENT || "?";
|
|
66
|
+
const role = env.ABAP_AI_ENV_ROLE || "DEVELOPMENT";
|
|
67
|
+
const tag = role === "PRODUCTION" ? "PRD" : role === "QUALITY" ? "QAS" : "DEV";
|
|
68
|
+
return {
|
|
69
|
+
title: `${name} (${url}, client ${client}, ${tag})`,
|
|
70
|
+
value: name,
|
|
71
|
+
selected: true,
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
const { selected } = await (0, prompts_1.default)({
|
|
75
|
+
type: "multiselect",
|
|
76
|
+
name: "selected",
|
|
77
|
+
message: "Selecione os sistemas SAP para este workspace",
|
|
78
|
+
choices,
|
|
79
|
+
hint: "Espaço para marcar/desmarcar, Enter para confirmar",
|
|
80
|
+
min: 1,
|
|
81
|
+
}, {
|
|
82
|
+
onCancel: () => {
|
|
83
|
+
console.log("\n Cancelado.\n");
|
|
84
|
+
process.exit(0);
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
if (!selected || selected.length === 0) {
|
|
88
|
+
console.log("\n Nenhum sistema selecionado.\n");
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
// Monta config local apenas com os sistemas escolhidos
|
|
92
|
+
const localConfig = { mcpServers: {} };
|
|
93
|
+
for (const name of selected) {
|
|
94
|
+
localConfig.mcpServers[name] = globalConfig.mcpServers[name];
|
|
95
|
+
}
|
|
96
|
+
// Verifica se já existe .mcp.json local e avisa sobre merge
|
|
97
|
+
const existingLocal = (0, init_js_1.readMcpConfig)(LOCAL_MCP_PATH);
|
|
98
|
+
const existingAbap = Object.keys(existingLocal.mcpServers).filter((k) => k.startsWith("abap-"));
|
|
99
|
+
if (existingAbap.length > 0) {
|
|
100
|
+
const { overwrite } = await (0, prompts_1.default)({
|
|
101
|
+
type: "confirm",
|
|
102
|
+
name: "overwrite",
|
|
103
|
+
message: `Este workspace já tem ${existingAbap.length} sistema(s) configurado(s). Substituir?`,
|
|
104
|
+
initial: false,
|
|
105
|
+
});
|
|
106
|
+
if (!overwrite) {
|
|
107
|
+
console.log("\n Operação cancelada. Configuração local mantida.\n");
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
// Preserva servidores não-abap que existam no .mcp.json local
|
|
111
|
+
for (const [k, v] of Object.entries(existingLocal.mcpServers)) {
|
|
112
|
+
if (!k.startsWith("abap-")) {
|
|
113
|
+
localConfig.mcpServers[k] = v;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Grava os 3 arquivos locais
|
|
118
|
+
(0, init_js_1.writeMcpConfig)(localConfig, LOCAL_MCP_PATH);
|
|
119
|
+
const claudeMdPath = path.join(process.cwd(), "CLAUDE.md");
|
|
120
|
+
(0, init_js_1.updateClaudeMd)(claudeMdPath, localConfig);
|
|
121
|
+
(0, init_js_1.writeClaudeSettings)(process.cwd());
|
|
122
|
+
// Relatório final
|
|
123
|
+
console.log(`
|
|
124
|
+
✓ Workspace configurado!
|
|
125
|
+
|
|
126
|
+
╭──────────────────────────────────────────────╮
|
|
127
|
+
│ Arquivos criados/atualizados: │`);
|
|
128
|
+
console.log(` │ • .mcp.json (servidores MCP) │`);
|
|
129
|
+
console.log(` │ • CLAUDE.md (contexto + políticas)│`);
|
|
130
|
+
console.log(` │ • .claude/settings.json (hooks segurança) │`);
|
|
131
|
+
console.log(` │ │`);
|
|
132
|
+
console.log(` │ ${selected.length} sistema(s) vinculado(s):${" ".repeat(Math.max(0, 24 - selected.length.toString().length))}│`);
|
|
133
|
+
for (const name of selected) {
|
|
134
|
+
const env = localConfig.mcpServers[name]?.env || {};
|
|
135
|
+
const client = env.SAP_CLIENT || "?";
|
|
136
|
+
const role = env.ABAP_AI_ENV_ROLE || "DEVELOPMENT";
|
|
137
|
+
const tag = role === "PRODUCTION" ? "PRD" : role === "QUALITY" ? "QAS" : "DEV";
|
|
138
|
+
const line = ` │ • ${name} (client ${client}, ${tag})`;
|
|
139
|
+
console.log(`${line}${" ".repeat(Math.max(1, 48 - line.length))}│`);
|
|
140
|
+
}
|
|
141
|
+
console.log(` │ │
|
|
142
|
+
│ Próximo passo no VS Code: │
|
|
143
|
+
│ 1. Ctrl+Shift+P → "Reload Window" │
|
|
144
|
+
│ 2. Clique "Allow" no aviso do MCP │
|
|
145
|
+
│ 3. Converse com o Claude Code! │
|
|
146
|
+
╰──────────────────────────────────────────────╯
|
|
147
|
+
`);
|
|
148
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.remove = remove;
|
|
40
|
+
const prompts_1 = __importDefault(require("prompts"));
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const os = __importStar(require("os"));
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
const GLOBAL_MCP_PATH = path.join(os.homedir(), ".claude", "mcp.json");
|
|
45
|
+
const LOCAL_MCP_PATH = path.join(process.cwd(), ".mcp.json");
|
|
46
|
+
async function remove(name, options = {}) {
|
|
47
|
+
const serverName = name.startsWith("abap-") ? name : `abap-${name}`;
|
|
48
|
+
const mcpPath = options.local ? LOCAL_MCP_PATH : GLOBAL_MCP_PATH;
|
|
49
|
+
let config;
|
|
50
|
+
try {
|
|
51
|
+
const raw = fs.readFileSync(mcpPath, "utf-8");
|
|
52
|
+
config = JSON.parse(raw);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
console.error(` ✗ Arquivo ${mcpPath} não encontrado.`);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (!config.mcpServers[serverName]) {
|
|
60
|
+
console.error(` ✗ Sistema "${serverName}" não encontrado no mcp.json.`);
|
|
61
|
+
const available = Object.keys(config.mcpServers).filter((k) => k.startsWith("abap-"));
|
|
62
|
+
if (available.length > 0) {
|
|
63
|
+
console.log(` Sistemas disponíveis: ${available.join(", ")}`);
|
|
64
|
+
}
|
|
65
|
+
process.exit(1);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const { confirm } = await (0, prompts_1.default)({
|
|
69
|
+
type: "confirm",
|
|
70
|
+
name: "confirm",
|
|
71
|
+
message: `Confirma remoção do sistema "${serverName}"?`,
|
|
72
|
+
initial: false,
|
|
73
|
+
});
|
|
74
|
+
if (!confirm) {
|
|
75
|
+
console.log(" Cancelado.\n");
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
delete config.mcpServers[serverName];
|
|
79
|
+
fs.writeFileSync(mcpPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
80
|
+
const remaining = Object.keys(config.mcpServers).filter((k) => k.startsWith("abap-")).length;
|
|
81
|
+
console.log(`\n ✓ Sistema "${serverName}" removido de ${mcpPath}`);
|
|
82
|
+
console.log(` ${remaining} sistema(s) restante(s).\n`);
|
|
83
|
+
}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.status = status;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const os = __importStar(require("os"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const https = __importStar(require("https"));
|
|
41
|
+
const http = __importStar(require("http"));
|
|
42
|
+
const activate_js_1 = require("./activate.js");
|
|
43
|
+
const MCP_JSON_PATH = path.join(os.homedir(), ".claude", "mcp.json");
|
|
44
|
+
const LOG_DIR = path.join(os.homedir(), ".abap-ai", "logs");
|
|
45
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
46
|
+
const VERSION = require("../../package.json").version;
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
// Teste rápido de conexão (timeout 5s)
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
async function quickTest(url, user, pass, client, selfSigned) {
|
|
51
|
+
const parsed = new URL(`${url}/sap/bc/adt/discovery`);
|
|
52
|
+
return new Promise((resolve) => {
|
|
53
|
+
const transport = parsed.protocol === "https:" ? https : http;
|
|
54
|
+
const req = transport.request({
|
|
55
|
+
hostname: parsed.hostname,
|
|
56
|
+
port: parsed.port || (parsed.protocol === "https:" ? 443 : 80),
|
|
57
|
+
path: parsed.pathname,
|
|
58
|
+
method: "GET",
|
|
59
|
+
headers: {
|
|
60
|
+
Authorization: "Basic " + Buffer.from(`${user}:${pass}`).toString("base64"),
|
|
61
|
+
"sap-client": client,
|
|
62
|
+
Accept: "application/atomsvc+xml",
|
|
63
|
+
},
|
|
64
|
+
rejectUnauthorized: !selfSigned,
|
|
65
|
+
timeout: 5000,
|
|
66
|
+
}, (res) => {
|
|
67
|
+
let body = "";
|
|
68
|
+
res.on("data", (chunk) => (body += chunk));
|
|
69
|
+
res.on("end", () => {
|
|
70
|
+
if (res.statusCode === 200) {
|
|
71
|
+
// Extrair info básica
|
|
72
|
+
const versionMatch = body.match(/release="(\d+)"/i);
|
|
73
|
+
const version = versionMatch ? `BASIS ${versionMatch[1]}` : "";
|
|
74
|
+
resolve({ ok: true, info: version || "OK" });
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
resolve({ ok: false, info: `HTTP ${res.statusCode}` });
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
req.on("error", () => resolve({ ok: false, info: "Sem conexão" }));
|
|
82
|
+
req.on("timeout", () => { req.destroy(); resolve({ ok: false, info: "Timeout" }); });
|
|
83
|
+
req.end();
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
// Métricas do dia (do logger)
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
function getTodayMetrics() {
|
|
90
|
+
const today = new Date().toISOString().split("T")[0];
|
|
91
|
+
const logFile = path.join(LOG_DIR, `adt-${today}.jsonl`);
|
|
92
|
+
if (!fs.existsSync(logFile)) {
|
|
93
|
+
return { calls: 0, success: 0, errors: 0, avgMs: 0 };
|
|
94
|
+
}
|
|
95
|
+
const lines = fs.readFileSync(logFile, "utf-8").trim().split("\n").filter(Boolean);
|
|
96
|
+
let success = 0;
|
|
97
|
+
let errors = 0;
|
|
98
|
+
let totalMs = 0;
|
|
99
|
+
for (const line of lines) {
|
|
100
|
+
try {
|
|
101
|
+
const entry = JSON.parse(line);
|
|
102
|
+
if (entry.status && entry.status < 400) {
|
|
103
|
+
success++;
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
errors++;
|
|
107
|
+
}
|
|
108
|
+
if (entry.duration)
|
|
109
|
+
totalMs += entry.duration;
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
// skip malformed lines
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const calls = success + errors;
|
|
116
|
+
return { calls, success, errors, avgMs: calls > 0 ? Math.round(totalMs / calls) : 0 };
|
|
117
|
+
}
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
// Contar knowledge files
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
function countKnowledge() {
|
|
122
|
+
// Tentar dist/knowledge primeiro, depois src/knowledge
|
|
123
|
+
const candidates = [
|
|
124
|
+
path.resolve(__dirname, "..", "knowledge"),
|
|
125
|
+
path.resolve(process.cwd(), "src", "knowledge"),
|
|
126
|
+
path.resolve(process.cwd(), "dist", "knowledge"),
|
|
127
|
+
];
|
|
128
|
+
for (const dir of candidates) {
|
|
129
|
+
if (fs.existsSync(dir)) {
|
|
130
|
+
let files = 0;
|
|
131
|
+
let domains = 0;
|
|
132
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
133
|
+
for (const entry of entries) {
|
|
134
|
+
if (entry.isDirectory()) {
|
|
135
|
+
domains++;
|
|
136
|
+
const domainFiles = fs.readdirSync(path.join(dir, entry.name)).filter((f) => f.endsWith(".md"));
|
|
137
|
+
files += domainFiles.length;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return { files, domains };
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return { files: 0, domains: 0 };
|
|
144
|
+
}
|
|
145
|
+
// ---------------------------------------------------------------------------
|
|
146
|
+
// Main
|
|
147
|
+
// ---------------------------------------------------------------------------
|
|
148
|
+
async function status() {
|
|
149
|
+
console.log(`
|
|
150
|
+
╭──────────────────────────────────────────────╮
|
|
151
|
+
│ LKPABAP.ai v${VERSION}${" ".repeat(30 - VERSION.length)}│
|
|
152
|
+
╰──────────────────────────────────────────────╯`);
|
|
153
|
+
// Licença
|
|
154
|
+
console.log(`
|
|
155
|
+
Licença
|
|
156
|
+
───────`);
|
|
157
|
+
const license = (0, activate_js_1.readLicense)();
|
|
158
|
+
if (license) {
|
|
159
|
+
const now = new Date();
|
|
160
|
+
const expires = new Date(license.expires);
|
|
161
|
+
const daysLeft = Math.ceil((expires.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
|
|
162
|
+
const expired = daysLeft <= 0;
|
|
163
|
+
const planLabel = `${license.plan.charAt(0).toUpperCase() + license.plan.slice(1)} (BYOK)`;
|
|
164
|
+
console.log(` Plano: ${planLabel}`);
|
|
165
|
+
console.log(` Válido até: ${license.expires} (${expired ? "EXPIRADA" : `${daysLeft} dias restantes`})`);
|
|
166
|
+
console.log(` Status: ${expired ? "✗ Expirada — renove em https://lkpabap.ai" : "✓ Ativa"}`);
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
console.log(` Status: ✗ Nenhuma licença configurada`);
|
|
170
|
+
console.log(` → Execute: abap-ai activate <LICENSE_KEY>`);
|
|
171
|
+
}
|
|
172
|
+
// Sistemas SAP
|
|
173
|
+
console.log(`
|
|
174
|
+
Sistemas SAP configurados
|
|
175
|
+
─────────────────────────`);
|
|
176
|
+
let mcpConfig = { mcpServers: {} };
|
|
177
|
+
try {
|
|
178
|
+
const raw = fs.readFileSync(MCP_JSON_PATH, "utf-8");
|
|
179
|
+
mcpConfig = JSON.parse(raw);
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
// no mcp.json
|
|
183
|
+
}
|
|
184
|
+
const sapServers = Object.entries(mcpConfig.mcpServers || {}).filter(([k]) => k.startsWith("abap-"));
|
|
185
|
+
if (sapServers.length === 0) {
|
|
186
|
+
console.log(` Nenhum configurado`);
|
|
187
|
+
console.log(` → Execute: abap-ai init`);
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
for (const [name, server] of sapServers) {
|
|
191
|
+
const env = server.env || {};
|
|
192
|
+
const url = env.SAP_URL || "?";
|
|
193
|
+
const client = env.SAP_CLIENT || "?";
|
|
194
|
+
const selfSigned = env.NODE_TLS_REJECT_UNAUTHORIZED === "0";
|
|
195
|
+
const shortUrl = url.replace(/^https?:\/\//, "").replace(/\.local$/, "");
|
|
196
|
+
if (env.SAP_URL && env.SAP_USER && env.SAP_PASS) {
|
|
197
|
+
const result = await quickTest(env.SAP_URL, env.SAP_USER, env.SAP_PASS, client, selfSigned);
|
|
198
|
+
if (result.ok) {
|
|
199
|
+
console.log(` ✓ ${name} ${shortUrl} (client ${client}) ${result.info}`);
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
console.log(` ✗ ${name} ${shortUrl} (client ${client}) ${result.info}`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
console.log(` ⚠ ${name} ${shortUrl} (client ${client}) Credenciais incompletas`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// Uso hoje
|
|
211
|
+
const metrics = getTodayMetrics();
|
|
212
|
+
if (metrics.calls > 0) {
|
|
213
|
+
const successRate = metrics.calls > 0 ? Math.round((metrics.success / metrics.calls) * 100) : 0;
|
|
214
|
+
console.log(`
|
|
215
|
+
Uso hoje
|
|
216
|
+
────────
|
|
217
|
+
Chamadas ADT: ${metrics.calls}
|
|
218
|
+
Sucesso: ${metrics.success} (${successRate}%)
|
|
219
|
+
Erros: ${metrics.errors}
|
|
220
|
+
Tempo médio: ${metrics.avgMs}ms`);
|
|
221
|
+
}
|
|
222
|
+
// Knowledge
|
|
223
|
+
const knowledge = countKnowledge();
|
|
224
|
+
if (knowledge.files > 0) {
|
|
225
|
+
console.log(`
|
|
226
|
+
Knowledge Base
|
|
227
|
+
──────────────
|
|
228
|
+
${knowledge.files} guias | ${knowledge.domains} domínios`);
|
|
229
|
+
}
|
|
230
|
+
console.log("");
|
|
231
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.systems = systems;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const os = __importStar(require("os"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const GLOBAL_MCP_PATH = path.join(os.homedir(), ".claude", "mcp.json");
|
|
41
|
+
const LOCAL_MCP_PATH = path.join(process.cwd(), ".mcp.json");
|
|
42
|
+
async function systems(options = {}) {
|
|
43
|
+
const mcpPath = options.local ? LOCAL_MCP_PATH : GLOBAL_MCP_PATH;
|
|
44
|
+
let config;
|
|
45
|
+
try {
|
|
46
|
+
const raw = fs.readFileSync(mcpPath, "utf-8");
|
|
47
|
+
config = JSON.parse(raw);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
console.log("\n Nenhum sistema configurado.");
|
|
51
|
+
console.log(` → Execute: abap-ai init${options.local ? " --local" : ""}\n`);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const sapServers = Object.entries(config.mcpServers || {}).filter(([k]) => k.startsWith("abap-"));
|
|
55
|
+
if (sapServers.length === 0) {
|
|
56
|
+
console.log("\n Nenhum sistema SAP configurado.");
|
|
57
|
+
console.log(` → Execute: abap-ai init${options.local ? " --local" : ""}\n`);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const scope = options.local ? `projeto (${process.cwd()})` : "global";
|
|
61
|
+
console.log(`\n Sistemas SAP (${sapServers.length}) — ${scope}:`);
|
|
62
|
+
console.log(" " + "─".repeat(60));
|
|
63
|
+
for (const [name, server] of sapServers) {
|
|
64
|
+
const env = server.env || {};
|
|
65
|
+
const url = (env.SAP_URL || "?").replace(/^https?:\/\//, "");
|
|
66
|
+
const client = env.SAP_CLIENT || "?";
|
|
67
|
+
const user = env.SAP_USER || "?";
|
|
68
|
+
const ssl = env.NODE_TLS_REJECT_UNAUTHORIZED === "0" ? " [SSL:off]" : "";
|
|
69
|
+
console.log(` ${name} ${url} client=${client} user=${user}${ssl}`);
|
|
70
|
+
}
|
|
71
|
+
console.log("");
|
|
72
|
+
}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const init_js_1 = require("./cli/init.js");
|
|
5
|
+
const activate_js_1 = require("./cli/activate.js");
|
|
6
|
+
const status_js_1 = require("./cli/status.js");
|
|
7
|
+
const remove_js_1 = require("./cli/remove.js");
|
|
8
|
+
const systems_js_1 = require("./cli/systems.js");
|
|
9
|
+
const link_js_1 = require("./cli/link.js");
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
11
|
+
const VERSION = require("../package.json").version;
|
|
12
|
+
const HELP = `
|
|
13
|
+
LKPABAP.ai — AI-powered ABAP development for SAP
|
|
14
|
+
|
|
15
|
+
Uso:
|
|
16
|
+
abap-ai <comando> [opções]
|
|
17
|
+
|
|
18
|
+
Comandos:
|
|
19
|
+
init [--local] Configura conexão com sistema SAP (wizard interativo)
|
|
20
|
+
link Vincula sistemas globais a este workspace (VS Code)
|
|
21
|
+
activate <LICENSE_KEY> Ativa licença do produto
|
|
22
|
+
status Mostra licença, sistemas e métricas de uso
|
|
23
|
+
systems [--local] Lista sistemas SAP configurados
|
|
24
|
+
remove <nome> [--local] Remove um sistema SAP do mcp.json
|
|
25
|
+
|
|
26
|
+
Opções:
|
|
27
|
+
--local Usa config do projeto atual (.claude/mcp.json) em vez do global
|
|
28
|
+
--version, -v Mostra versão
|
|
29
|
+
--help, -h Mostra esta ajuda
|
|
30
|
+
|
|
31
|
+
Exemplos:
|
|
32
|
+
abap-ai init Wizard global (todos os workspaces)
|
|
33
|
+
abap-ai init --local Wizard para este workspace/projeto apenas
|
|
34
|
+
abap-ai link Vincula sistemas SAP a este workspace (necessário no VS Code)
|
|
35
|
+
abap-ai activate LK-XXXX Ativa licença
|
|
36
|
+
abap-ai status Verifica estado do ambiente
|
|
37
|
+
abap-ai remove novaforma-qas Remove sistema (config global)
|
|
38
|
+
abap-ai remove rdg --local Remove sistema da config do projeto
|
|
39
|
+
`;
|
|
40
|
+
async function main() {
|
|
41
|
+
const args = process.argv.slice(2);
|
|
42
|
+
const command = args[0];
|
|
43
|
+
if (!command || command === "--help" || command === "-h") {
|
|
44
|
+
console.log(HELP);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (command === "--version" || command === "-v") {
|
|
48
|
+
console.log(`LKPABAP.ai v${VERSION}`);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const local = args.includes("--local");
|
|
52
|
+
switch (command) {
|
|
53
|
+
case "init":
|
|
54
|
+
await (0, init_js_1.init)({ local });
|
|
55
|
+
break;
|
|
56
|
+
case "activate": {
|
|
57
|
+
const key = args[1];
|
|
58
|
+
if (!key) {
|
|
59
|
+
console.error(" ✗ Informe a license key: abap-ai activate LK-XXXX-XXXX-XXXX");
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
await (0, activate_js_1.activate)(key);
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
case "status":
|
|
66
|
+
await (0, status_js_1.status)();
|
|
67
|
+
break;
|
|
68
|
+
case "link":
|
|
69
|
+
await (0, link_js_1.link)();
|
|
70
|
+
break;
|
|
71
|
+
case "systems":
|
|
72
|
+
await (0, systems_js_1.systems)({ local });
|
|
73
|
+
break;
|
|
74
|
+
case "remove": {
|
|
75
|
+
const name = args.filter((a) => !a.startsWith("--"))[1];
|
|
76
|
+
if (!name) {
|
|
77
|
+
console.error(" ✗ Informe o nome do sistema: abap-ai remove <nome>");
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
await (0, remove_js_1.remove)(name, { local });
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
default:
|
|
84
|
+
console.error(` ✗ Comando desconhecido: "${command}"`);
|
|
85
|
+
console.log(HELP);
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
main().catch((err) => {
|
|
90
|
+
console.error(` ✗ Erro: ${err.message || err}`);
|
|
91
|
+
process.exit(1);
|
|
92
|
+
});
|