@linkup-ai/abap-ai 2.0.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 +384 -0
- package/dist/adt-client.js +364 -0
- package/dist/cli/activate.js +113 -0
- package/dist/cli/init.js +333 -0
- package/dist/cli/remove.js +80 -0
- package/dist/cli/status.js +229 -0
- package/dist/cli/systems.js +68 -0
- package/dist/cli.js +81 -0
- package/dist/index.js +1318 -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/logger.js +114 -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 +68 -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 +167 -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 +270 -0
- package/dist/tools/traces.js +66 -0
- package/dist/tools/transport-contents.js +83 -0
- package/dist/tools/transports.js +67 -0
- package/dist/tools/unit-test.js +135 -0
- package/dist/tools/where-used.js +59 -0
- package/dist/tools/write.js +101 -0
- package/package.json +49 -0
package/dist/cli/init.js
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
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.init = init;
|
|
40
|
+
const prompts_1 = __importDefault(require("prompts"));
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
const https = __importStar(require("https"));
|
|
44
|
+
const http = __importStar(require("http"));
|
|
45
|
+
const MCP_JSON_PATH = path.join(process.env.HOME || "~", ".claude", "mcp.json");
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
// Teste de conexão SAP
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
async function testConnection(system) {
|
|
50
|
+
const url = new URL(`${system.url}/sap/bc/adt/discovery`);
|
|
51
|
+
const options = {
|
|
52
|
+
hostname: url.hostname,
|
|
53
|
+
port: url.port || (url.protocol === "https:" ? 443 : 80),
|
|
54
|
+
path: url.pathname,
|
|
55
|
+
method: "GET",
|
|
56
|
+
headers: {
|
|
57
|
+
Authorization: "Basic " + Buffer.from(`${system.user}:${system.pass}`).toString("base64"),
|
|
58
|
+
"sap-client": system.client,
|
|
59
|
+
"sap-language": system.language,
|
|
60
|
+
Accept: "application/atomsvc+xml",
|
|
61
|
+
},
|
|
62
|
+
rejectAuthorized: !system.selfSignedSsl,
|
|
63
|
+
timeout: 10000,
|
|
64
|
+
};
|
|
65
|
+
// workaround: rejectUnauthorized
|
|
66
|
+
if (system.selfSignedSsl) {
|
|
67
|
+
options.rejectUnauthorized = false;
|
|
68
|
+
}
|
|
69
|
+
return new Promise((resolve) => {
|
|
70
|
+
const transport = url.protocol === "https:" ? https : http;
|
|
71
|
+
const req = transport.request(options, (res) => {
|
|
72
|
+
let body = "";
|
|
73
|
+
res.on("data", (chunk) => (body += chunk));
|
|
74
|
+
res.on("end", () => {
|
|
75
|
+
if (res.statusCode === 200) {
|
|
76
|
+
// Contar APIs
|
|
77
|
+
const apiCount = (body.match(/<(?:app:)?collection/gi) || []).length;
|
|
78
|
+
// Tentar extrair versão
|
|
79
|
+
const versionMatch = body.match(/SAP_BASIS\s+(\d+)/i) || body.match(/release="(\d+)"/i);
|
|
80
|
+
const version = versionMatch ? `BASIS ${versionMatch[1]}` : "";
|
|
81
|
+
resolve({ ok: true, info: `${apiCount} APIs ADT disponíveis${version ? ` | ${version}` : ""}` });
|
|
82
|
+
}
|
|
83
|
+
else if (res.statusCode === 401) {
|
|
84
|
+
resolve({ ok: false, info: "Credenciais inválidas (401)" });
|
|
85
|
+
}
|
|
86
|
+
else if (res.statusCode === 403) {
|
|
87
|
+
resolve({ ok: false, info: "Sem autorização para ADT (403). Verifique perfil S_ADT_RES." });
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
resolve({ ok: false, info: `HTTP ${res.statusCode}: ${res.statusMessage}` });
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
req.on("error", (err) => {
|
|
95
|
+
if (err.code === "ECONNREFUSED") {
|
|
96
|
+
resolve({ ok: false, info: "Conexão recusada. Verifique URL e porta." });
|
|
97
|
+
}
|
|
98
|
+
else if (err.code === "ETIMEDOUT" || err.code === "ESOCKETTIMEDOUT") {
|
|
99
|
+
resolve({ ok: false, info: "Timeout. Verifique VPN e firewall." });
|
|
100
|
+
}
|
|
101
|
+
else if (err.message.includes("certificate") || err.message.includes("SSL")) {
|
|
102
|
+
resolve({ ok: false, info: "Erro SSL. Marque 'Sim' para certificado self-signed." });
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
resolve({ ok: false, info: err.message });
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
req.on("timeout", () => {
|
|
109
|
+
req.destroy();
|
|
110
|
+
resolve({ ok: false, info: "Timeout (10s). Verifique VPN e firewall." });
|
|
111
|
+
});
|
|
112
|
+
req.end();
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
// mcp.json management
|
|
117
|
+
// ---------------------------------------------------------------------------
|
|
118
|
+
function readMcpConfig() {
|
|
119
|
+
try {
|
|
120
|
+
const raw = fs.readFileSync(MCP_JSON_PATH, "utf-8");
|
|
121
|
+
return JSON.parse(raw);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return { mcpServers: {} };
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function writeMcpConfig(config) {
|
|
128
|
+
const dir = path.dirname(MCP_JSON_PATH);
|
|
129
|
+
if (!fs.existsSync(dir)) {
|
|
130
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
131
|
+
}
|
|
132
|
+
fs.writeFileSync(MCP_JSON_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
133
|
+
}
|
|
134
|
+
function detectServerPath() {
|
|
135
|
+
// Tentar encontrar o index.js relativo ao CLI
|
|
136
|
+
const fromCli = path.resolve(__dirname, "..", "index.js");
|
|
137
|
+
if (fs.existsSync(fromCli))
|
|
138
|
+
return fromCli;
|
|
139
|
+
// Fallback: path global do pacote
|
|
140
|
+
const globalPath = path.resolve(__dirname, "..", "index.js");
|
|
141
|
+
return globalPath;
|
|
142
|
+
}
|
|
143
|
+
function addSystemToConfig(config, system) {
|
|
144
|
+
const serverName = `abap-${system.name}`;
|
|
145
|
+
const serverPath = detectServerPath();
|
|
146
|
+
const env = {
|
|
147
|
+
SAP_URL: system.url,
|
|
148
|
+
SAP_CLIENT: system.client,
|
|
149
|
+
SAP_USER: system.user,
|
|
150
|
+
SAP_PASS: system.pass,
|
|
151
|
+
SAP_LANGUAGE: system.language,
|
|
152
|
+
};
|
|
153
|
+
if (system.selfSignedSsl) {
|
|
154
|
+
env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
155
|
+
}
|
|
156
|
+
config.mcpServers[serverName] = {
|
|
157
|
+
command: "node",
|
|
158
|
+
args: [serverPath],
|
|
159
|
+
env,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
// ---------------------------------------------------------------------------
|
|
163
|
+
// Wizard
|
|
164
|
+
// ---------------------------------------------------------------------------
|
|
165
|
+
async function promptSystem() {
|
|
166
|
+
const response = await (0, prompts_1.default)([
|
|
167
|
+
{
|
|
168
|
+
type: "text",
|
|
169
|
+
name: "name",
|
|
170
|
+
message: "Nome deste sistema (identificador curto)",
|
|
171
|
+
validate: (v) => v.trim().length > 0 ? true : "Informe um nome (ex: novaforma-dev)",
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
type: "text",
|
|
175
|
+
name: "url",
|
|
176
|
+
message: "URL do SAP (com porta)",
|
|
177
|
+
validate: (v) => {
|
|
178
|
+
try {
|
|
179
|
+
new URL(v);
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
return "URL inválida (ex: https://sap-host:8443)";
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
type: "text",
|
|
189
|
+
name: "client",
|
|
190
|
+
message: "Client (mandant)",
|
|
191
|
+
initial: "100",
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
type: "text",
|
|
195
|
+
name: "user",
|
|
196
|
+
message: "Usuário SAP",
|
|
197
|
+
validate: (v) => v.trim().length > 0 ? true : "Informe o usuário",
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
type: "password",
|
|
201
|
+
name: "pass",
|
|
202
|
+
message: "Senha SAP",
|
|
203
|
+
validate: (v) => v.length > 0 ? true : "Informe a senha",
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
type: "text",
|
|
207
|
+
name: "language",
|
|
208
|
+
message: "Idioma (EN, PT, DE...)",
|
|
209
|
+
initial: "PT",
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
type: "confirm",
|
|
213
|
+
name: "selfSignedSsl",
|
|
214
|
+
message: "Certificado SSL self-signed?",
|
|
215
|
+
initial: true,
|
|
216
|
+
},
|
|
217
|
+
], {
|
|
218
|
+
onCancel: () => {
|
|
219
|
+
console.log("\n Cancelado.");
|
|
220
|
+
process.exit(0);
|
|
221
|
+
},
|
|
222
|
+
});
|
|
223
|
+
if (!response.name || !response.url || !response.user || !response.pass) {
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
return {
|
|
227
|
+
name: response.name.trim().toLowerCase().replace(/\s+/g, "-"),
|
|
228
|
+
url: response.url.trim().replace(/\/+$/, ""),
|
|
229
|
+
client: response.client?.trim() || "100",
|
|
230
|
+
user: response.user.trim().toUpperCase(),
|
|
231
|
+
pass: response.pass,
|
|
232
|
+
language: (response.language?.trim() || "PT").toUpperCase(),
|
|
233
|
+
selfSignedSsl: response.selfSignedSsl ?? true,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
// ---------------------------------------------------------------------------
|
|
237
|
+
// Main
|
|
238
|
+
// ---------------------------------------------------------------------------
|
|
239
|
+
async function init() {
|
|
240
|
+
console.log(`
|
|
241
|
+
╭─────────────────────────────────────╮
|
|
242
|
+
│ LKPABAP.ia — Setup │
|
|
243
|
+
│ Conecte o Claude ao seu SAP │
|
|
244
|
+
╰─────────────────────────────────────╯
|
|
245
|
+
`);
|
|
246
|
+
const config = readMcpConfig();
|
|
247
|
+
const existingCount = Object.keys(config.mcpServers).filter((k) => k.startsWith("abap-")).length;
|
|
248
|
+
if (existingCount > 0) {
|
|
249
|
+
console.log(` ${existingCount} sistema(s) SAP já configurado(s).\n`);
|
|
250
|
+
}
|
|
251
|
+
const addedSystems = [];
|
|
252
|
+
let addMore = true;
|
|
253
|
+
while (addMore) {
|
|
254
|
+
const system = await promptSystem();
|
|
255
|
+
if (!system)
|
|
256
|
+
break;
|
|
257
|
+
const serverName = `abap-${system.name}`;
|
|
258
|
+
// Verificar duplicata
|
|
259
|
+
if (config.mcpServers[serverName]) {
|
|
260
|
+
const { overwrite } = await (0, prompts_1.default)({
|
|
261
|
+
type: "confirm",
|
|
262
|
+
name: "overwrite",
|
|
263
|
+
message: `Sistema "${serverName}" já existe. Sobrescrever?`,
|
|
264
|
+
initial: false,
|
|
265
|
+
});
|
|
266
|
+
if (!overwrite)
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
// Testar conexão
|
|
270
|
+
console.log("\n ⏳ Testando conexão com SAP...");
|
|
271
|
+
const result = await testConnection(system);
|
|
272
|
+
if (result.ok) {
|
|
273
|
+
console.log(` ✓ Conectado! ${result.info}\n`);
|
|
274
|
+
addSystemToConfig(config, system);
|
|
275
|
+
addedSystems.push(system.name);
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
console.log(` ✗ Falha: ${result.info}\n`);
|
|
279
|
+
const { retry } = await (0, prompts_1.default)({
|
|
280
|
+
type: "select",
|
|
281
|
+
name: "retry",
|
|
282
|
+
message: "O que deseja fazer?",
|
|
283
|
+
choices: [
|
|
284
|
+
{ title: "Tentar novamente com outros dados", value: "retry" },
|
|
285
|
+
{ title: "Adicionar mesmo assim (sem validar)", value: "force" },
|
|
286
|
+
{ title: "Pular este sistema", value: "skip" },
|
|
287
|
+
],
|
|
288
|
+
});
|
|
289
|
+
if (retry === "force") {
|
|
290
|
+
addSystemToConfig(config, system);
|
|
291
|
+
addedSystems.push(system.name);
|
|
292
|
+
console.log(` ⚠️ Sistema adicionado sem validação.\n`);
|
|
293
|
+
}
|
|
294
|
+
else if (retry === "retry") {
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
// skip
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
const { more } = await (0, prompts_1.default)({
|
|
302
|
+
type: "confirm",
|
|
303
|
+
name: "more",
|
|
304
|
+
message: "Deseja adicionar outro sistema?",
|
|
305
|
+
initial: false,
|
|
306
|
+
});
|
|
307
|
+
addMore = more;
|
|
308
|
+
}
|
|
309
|
+
if (addedSystems.length > 0) {
|
|
310
|
+
writeMcpConfig(config);
|
|
311
|
+
const total = Object.keys(config.mcpServers).filter((k) => k.startsWith("abap-")).length;
|
|
312
|
+
console.log(`
|
|
313
|
+
✓ Configuração salva em ${MCP_JSON_PATH}
|
|
314
|
+
|
|
315
|
+
╭──────────────────────────────────────────────╮
|
|
316
|
+
│ ${total} sistema(s) configurado(s):${" ".repeat(Math.max(0, 23 - total.toString().length))}│`);
|
|
317
|
+
for (const name of addedSystems) {
|
|
318
|
+
const sn = `abap-${name}`;
|
|
319
|
+
const env = config.mcpServers[sn]?.env || {};
|
|
320
|
+
const client = env.SAP_CLIENT || "?";
|
|
321
|
+
const line = ` │ • ${name} (client ${client})`;
|
|
322
|
+
console.log(`${line}${" ".repeat(Math.max(1, 48 - line.length))}│`);
|
|
323
|
+
}
|
|
324
|
+
console.log(` │${" ".repeat(46)}│
|
|
325
|
+
│ Próximo passo:${" ".repeat(29)}│
|
|
326
|
+
│ Abra o VS Code / Claude Code e use!${" ".repeat(6)}│
|
|
327
|
+
╰──────────────────────────────────────────────╯
|
|
328
|
+
`);
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
console.log("\n Nenhum sistema adicionado.\n");
|
|
332
|
+
}
|
|
333
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
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 path = __importStar(require("path"));
|
|
43
|
+
const MCP_JSON_PATH = path.join(process.env.HOME || "~", ".claude", "mcp.json");
|
|
44
|
+
async function remove(name) {
|
|
45
|
+
const serverName = name.startsWith("abap-") ? name : `abap-${name}`;
|
|
46
|
+
let config;
|
|
47
|
+
try {
|
|
48
|
+
const raw = fs.readFileSync(MCP_JSON_PATH, "utf-8");
|
|
49
|
+
config = JSON.parse(raw);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
console.error(` ✗ Arquivo ${MCP_JSON_PATH} não encontrado.`);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (!config.mcpServers[serverName]) {
|
|
57
|
+
console.error(` ✗ Sistema "${serverName}" não encontrado no mcp.json.`);
|
|
58
|
+
const available = Object.keys(config.mcpServers).filter((k) => k.startsWith("abap-"));
|
|
59
|
+
if (available.length > 0) {
|
|
60
|
+
console.log(` Sistemas disponíveis: ${available.join(", ")}`);
|
|
61
|
+
}
|
|
62
|
+
process.exit(1);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const { confirm } = await (0, prompts_1.default)({
|
|
66
|
+
type: "confirm",
|
|
67
|
+
name: "confirm",
|
|
68
|
+
message: `Confirma remoção do sistema "${serverName}"?`,
|
|
69
|
+
initial: false,
|
|
70
|
+
});
|
|
71
|
+
if (!confirm) {
|
|
72
|
+
console.log(" Cancelado.\n");
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
delete config.mcpServers[serverName];
|
|
76
|
+
fs.writeFileSync(MCP_JSON_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
77
|
+
const remaining = Object.keys(config.mcpServers).filter((k) => k.startsWith("abap-")).length;
|
|
78
|
+
console.log(`\n ✓ Sistema "${serverName}" removido de ${MCP_JSON_PATH}`);
|
|
79
|
+
console.log(` ${remaining} sistema(s) restante(s).\n`);
|
|
80
|
+
}
|
|
@@ -0,0 +1,229 @@
|
|
|
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 path = __importStar(require("path"));
|
|
39
|
+
const https = __importStar(require("https"));
|
|
40
|
+
const http = __importStar(require("http"));
|
|
41
|
+
const activate_js_1 = require("./activate.js");
|
|
42
|
+
const MCP_JSON_PATH = path.join(process.env.HOME || "~", ".claude", "mcp.json");
|
|
43
|
+
const LOG_DIR = path.join(process.env.HOME || "~", ".abap-ai", "logs");
|
|
44
|
+
const VERSION = "2.0.0";
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
// Teste rápido de conexão (timeout 5s)
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
async function quickTest(url, user, pass, client, selfSigned) {
|
|
49
|
+
const parsed = new URL(`${url}/sap/bc/adt/discovery`);
|
|
50
|
+
return new Promise((resolve) => {
|
|
51
|
+
const transport = parsed.protocol === "https:" ? https : http;
|
|
52
|
+
const req = transport.request({
|
|
53
|
+
hostname: parsed.hostname,
|
|
54
|
+
port: parsed.port || (parsed.protocol === "https:" ? 443 : 80),
|
|
55
|
+
path: parsed.pathname,
|
|
56
|
+
method: "GET",
|
|
57
|
+
headers: {
|
|
58
|
+
Authorization: "Basic " + Buffer.from(`${user}:${pass}`).toString("base64"),
|
|
59
|
+
"sap-client": client,
|
|
60
|
+
Accept: "application/atomsvc+xml",
|
|
61
|
+
},
|
|
62
|
+
rejectUnauthorized: !selfSigned,
|
|
63
|
+
timeout: 5000,
|
|
64
|
+
}, (res) => {
|
|
65
|
+
let body = "";
|
|
66
|
+
res.on("data", (chunk) => (body += chunk));
|
|
67
|
+
res.on("end", () => {
|
|
68
|
+
if (res.statusCode === 200) {
|
|
69
|
+
// Extrair info básica
|
|
70
|
+
const versionMatch = body.match(/release="(\d+)"/i);
|
|
71
|
+
const version = versionMatch ? `BASIS ${versionMatch[1]}` : "";
|
|
72
|
+
resolve({ ok: true, info: version || "OK" });
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
resolve({ ok: false, info: `HTTP ${res.statusCode}` });
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
req.on("error", () => resolve({ ok: false, info: "Sem conexão" }));
|
|
80
|
+
req.on("timeout", () => { req.destroy(); resolve({ ok: false, info: "Timeout" }); });
|
|
81
|
+
req.end();
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
// ---------------------------------------------------------------------------
|
|
85
|
+
// Métricas do dia (do logger)
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
function getTodayMetrics() {
|
|
88
|
+
const today = new Date().toISOString().split("T")[0];
|
|
89
|
+
const logFile = path.join(LOG_DIR, `adt-${today}.jsonl`);
|
|
90
|
+
if (!fs.existsSync(logFile)) {
|
|
91
|
+
return { calls: 0, success: 0, errors: 0, avgMs: 0 };
|
|
92
|
+
}
|
|
93
|
+
const lines = fs.readFileSync(logFile, "utf-8").trim().split("\n").filter(Boolean);
|
|
94
|
+
let success = 0;
|
|
95
|
+
let errors = 0;
|
|
96
|
+
let totalMs = 0;
|
|
97
|
+
for (const line of lines) {
|
|
98
|
+
try {
|
|
99
|
+
const entry = JSON.parse(line);
|
|
100
|
+
if (entry.status && entry.status < 400) {
|
|
101
|
+
success++;
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
errors++;
|
|
105
|
+
}
|
|
106
|
+
if (entry.duration)
|
|
107
|
+
totalMs += entry.duration;
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// skip malformed lines
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const calls = success + errors;
|
|
114
|
+
return { calls, success, errors, avgMs: calls > 0 ? Math.round(totalMs / calls) : 0 };
|
|
115
|
+
}
|
|
116
|
+
// ---------------------------------------------------------------------------
|
|
117
|
+
// Contar knowledge files
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
function countKnowledge() {
|
|
120
|
+
// Tentar dist/knowledge primeiro, depois src/knowledge
|
|
121
|
+
const candidates = [
|
|
122
|
+
path.resolve(__dirname, "..", "knowledge"),
|
|
123
|
+
path.resolve(process.cwd(), "src", "knowledge"),
|
|
124
|
+
path.resolve(process.cwd(), "dist", "knowledge"),
|
|
125
|
+
];
|
|
126
|
+
for (const dir of candidates) {
|
|
127
|
+
if (fs.existsSync(dir)) {
|
|
128
|
+
let files = 0;
|
|
129
|
+
let domains = 0;
|
|
130
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
131
|
+
for (const entry of entries) {
|
|
132
|
+
if (entry.isDirectory()) {
|
|
133
|
+
domains++;
|
|
134
|
+
const domainFiles = fs.readdirSync(path.join(dir, entry.name)).filter((f) => f.endsWith(".md"));
|
|
135
|
+
files += domainFiles.length;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return { files, domains };
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return { files: 0, domains: 0 };
|
|
142
|
+
}
|
|
143
|
+
// ---------------------------------------------------------------------------
|
|
144
|
+
// Main
|
|
145
|
+
// ---------------------------------------------------------------------------
|
|
146
|
+
async function status() {
|
|
147
|
+
console.log(`
|
|
148
|
+
╭──────────────────────────────────────────────╮
|
|
149
|
+
│ LKPABAP.ia v${VERSION}${" ".repeat(30 - VERSION.length)}│
|
|
150
|
+
╰──────────────────────────────────────────────╯`);
|
|
151
|
+
// Licença
|
|
152
|
+
console.log(`
|
|
153
|
+
Licença
|
|
154
|
+
───────`);
|
|
155
|
+
const license = (0, activate_js_1.readLicense)();
|
|
156
|
+
if (license) {
|
|
157
|
+
const now = new Date();
|
|
158
|
+
const expires = new Date(license.expires);
|
|
159
|
+
const daysLeft = Math.ceil((expires.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
|
|
160
|
+
const expired = daysLeft <= 0;
|
|
161
|
+
const planLabel = `${license.plan.charAt(0).toUpperCase() + license.plan.slice(1)} (${license.mode === "byok" ? "BYOK" : "All-in-One"})`;
|
|
162
|
+
console.log(` Plano: ${planLabel}`);
|
|
163
|
+
console.log(` Válido até: ${license.expires} (${expired ? "EXPIRADA" : `${daysLeft} dias restantes`})`);
|
|
164
|
+
console.log(` Status: ${expired ? "✗ Expirada — renove em https://lkpabap.ai" : "✓ Ativa"}`);
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
console.log(` Status: ✗ Nenhuma licença configurada`);
|
|
168
|
+
console.log(` → Execute: abap-ai activate <LICENSE_KEY>`);
|
|
169
|
+
}
|
|
170
|
+
// Sistemas SAP
|
|
171
|
+
console.log(`
|
|
172
|
+
Sistemas SAP configurados
|
|
173
|
+
─────────────────────────`);
|
|
174
|
+
let mcpConfig = { mcpServers: {} };
|
|
175
|
+
try {
|
|
176
|
+
const raw = fs.readFileSync(MCP_JSON_PATH, "utf-8");
|
|
177
|
+
mcpConfig = JSON.parse(raw);
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
// no mcp.json
|
|
181
|
+
}
|
|
182
|
+
const sapServers = Object.entries(mcpConfig.mcpServers || {}).filter(([k]) => k.startsWith("abap-"));
|
|
183
|
+
if (sapServers.length === 0) {
|
|
184
|
+
console.log(` Nenhum configurado`);
|
|
185
|
+
console.log(` → Execute: abap-ai init`);
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
for (const [name, server] of sapServers) {
|
|
189
|
+
const env = server.env || {};
|
|
190
|
+
const url = env.SAP_URL || "?";
|
|
191
|
+
const client = env.SAP_CLIENT || "?";
|
|
192
|
+
const selfSigned = env.NODE_TLS_REJECT_UNAUTHORIZED === "0";
|
|
193
|
+
const shortUrl = url.replace(/^https?:\/\//, "").replace(/\.local$/, "");
|
|
194
|
+
if (env.SAP_URL && env.SAP_USER && env.SAP_PASS) {
|
|
195
|
+
const result = await quickTest(env.SAP_URL, env.SAP_USER, env.SAP_PASS, client, selfSigned);
|
|
196
|
+
if (result.ok) {
|
|
197
|
+
console.log(` ✓ ${name} ${shortUrl} (client ${client}) ${result.info}`);
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
console.log(` ✗ ${name} ${shortUrl} (client ${client}) ${result.info}`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
console.log(` ⚠ ${name} ${shortUrl} (client ${client}) Credenciais incompletas`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// Uso hoje
|
|
209
|
+
const metrics = getTodayMetrics();
|
|
210
|
+
if (metrics.calls > 0) {
|
|
211
|
+
const successRate = metrics.calls > 0 ? Math.round((metrics.success / metrics.calls) * 100) : 0;
|
|
212
|
+
console.log(`
|
|
213
|
+
Uso hoje
|
|
214
|
+
────────
|
|
215
|
+
Chamadas ADT: ${metrics.calls}
|
|
216
|
+
Sucesso: ${metrics.success} (${successRate}%)
|
|
217
|
+
Erros: ${metrics.errors}
|
|
218
|
+
Tempo médio: ${metrics.avgMs}ms`);
|
|
219
|
+
}
|
|
220
|
+
// Knowledge
|
|
221
|
+
const knowledge = countKnowledge();
|
|
222
|
+
if (knowledge.files > 0) {
|
|
223
|
+
console.log(`
|
|
224
|
+
Knowledge Base
|
|
225
|
+
──────────────
|
|
226
|
+
${knowledge.files} guias | ${knowledge.domains} domínios`);
|
|
227
|
+
}
|
|
228
|
+
console.log("");
|
|
229
|
+
}
|