@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.
Files changed (119) hide show
  1. package/README.md +389 -0
  2. package/dist/adt-client.js +383 -0
  3. package/dist/cli/activate.js +127 -0
  4. package/dist/cli/init.js +559 -0
  5. package/dist/cli/link.js +148 -0
  6. package/dist/cli/remove.js +83 -0
  7. package/dist/cli/status.js +231 -0
  8. package/dist/cli/systems.js +72 -0
  9. package/dist/cli.js +92 -0
  10. package/dist/index.js +1442 -0
  11. package/dist/knowledge/abap/abap-dictionary.md +199 -0
  12. package/dist/knowledge/abap/abap-sql.md +296 -0
  13. package/dist/knowledge/abap/amdp.md +273 -0
  14. package/dist/knowledge/abap/clean-code.md +293 -0
  15. package/dist/knowledge/abap/cloud-background-processing.md +250 -0
  16. package/dist/knowledge/abap/cloud-communication.md +265 -0
  17. package/dist/knowledge/abap/cloud-development.md +176 -0
  18. package/dist/knowledge/abap/cloud-extensibility.md +252 -0
  19. package/dist/knowledge/abap/cloud-released-apis.md +261 -0
  20. package/dist/knowledge/abap/constructor-expressions.md +289 -0
  21. package/dist/knowledge/abap/enhancements.md +232 -0
  22. package/dist/knowledge/abap/exceptions.md +271 -0
  23. package/dist/knowledge/abap/internal-tables.md +205 -0
  24. package/dist/knowledge/abap/object-orientation.md +298 -0
  25. package/dist/knowledge/abap/performance.md +216 -0
  26. package/dist/knowledge/abap/rap-abstract-entities.md +206 -0
  27. package/dist/knowledge/abap/rap-business-events.md +216 -0
  28. package/dist/knowledge/abap/rap-draft.md +191 -0
  29. package/dist/knowledge/abap/rap-eml.md +453 -0
  30. package/dist/knowledge/abap/rap-end-to-end.md +486 -0
  31. package/dist/knowledge/abap/rap-feature-control.md +185 -0
  32. package/dist/knowledge/abap/rap-numbering.md +280 -0
  33. package/dist/knowledge/abap/rap-service-exposure.md +163 -0
  34. package/dist/knowledge/abap/rap-unmanaged.md +468 -0
  35. package/dist/knowledge/abap/string-processing.md +180 -0
  36. package/dist/knowledge/abap/unit-testing.md +303 -0
  37. package/dist/knowledge/abap-cds/access-control.md +241 -0
  38. package/dist/knowledge/abap-cds/annotations.md +331 -0
  39. package/dist/knowledge/abap-cds/associations.md +254 -0
  40. package/dist/knowledge/abap-cds/expressions.md +230 -0
  41. package/dist/knowledge/abap-cds/functions.md +245 -0
  42. package/dist/knowledge/abap-cds/metadata-extensions.md +294 -0
  43. package/dist/knowledge/cap/authentication.md +278 -0
  44. package/dist/knowledge/cap/cdl-syntax.md +247 -0
  45. package/dist/knowledge/cap/cql-queries.md +266 -0
  46. package/dist/knowledge/cap/deployment.md +343 -0
  47. package/dist/knowledge/cap/event-handlers.md +287 -0
  48. package/dist/knowledge/cap/fiori-integration.md +303 -0
  49. package/dist/knowledge/cap/service-definitions.md +287 -0
  50. package/dist/knowledge/fiori/annotations.md +347 -0
  51. package/dist/knowledge/fiori/deployment.md +340 -0
  52. package/dist/knowledge/fiori/fiori-elements.md +332 -0
  53. package/dist/knowledge/fiori/fiori-side-effects.md +107 -0
  54. package/dist/knowledge/fiori/fiori-valuelist.md +144 -0
  55. package/dist/knowledge/fiori/ui5-controllers.md +358 -0
  56. package/dist/knowledge/fiori/ui5-data-binding.md +311 -0
  57. package/dist/knowledge/fiori/ui5-fragments-dialogs.md +330 -0
  58. package/dist/knowledge/fiori/ui5-manifest.md +411 -0
  59. package/dist/knowledge/fiori/ui5-routing.md +303 -0
  60. package/dist/knowledge/fiori/ui5-xml-views.md +294 -0
  61. package/dist/license-guard.js +81 -0
  62. package/dist/logger.js +114 -0
  63. package/dist/postinstall.js +165 -0
  64. package/dist/security-audit.js +136 -0
  65. package/dist/security-policy.js +322 -0
  66. package/dist/system-profile.js +207 -0
  67. package/dist/tools/abap-doc.js +72 -0
  68. package/dist/tools/abapgit.js +161 -0
  69. package/dist/tools/activate.js +71 -0
  70. package/dist/tools/atc-check.js +117 -0
  71. package/dist/tools/auth-object.js +56 -0
  72. package/dist/tools/breakpoints.js +76 -0
  73. package/dist/tools/call-hierarchy.js +84 -0
  74. package/dist/tools/cds-annotations.js +98 -0
  75. package/dist/tools/cds-dependencies.js +65 -0
  76. package/dist/tools/check.js +47 -0
  77. package/dist/tools/code-completion.js +70 -0
  78. package/dist/tools/code-coverage.js +111 -0
  79. package/dist/tools/create-amdp.js +111 -0
  80. package/dist/tools/create-dcl.js +81 -0
  81. package/dist/tools/create-transport.js +38 -0
  82. package/dist/tools/create.js +285 -0
  83. package/dist/tools/data-preview.js +37 -0
  84. package/dist/tools/delete.js +45 -0
  85. package/dist/tools/deploy-bsp.js +298 -0
  86. package/dist/tools/discovery.js +59 -0
  87. package/dist/tools/element-info.js +93 -0
  88. package/dist/tools/enhancements.js +186 -0
  89. package/dist/tools/extract-method.js +44 -0
  90. package/dist/tools/function-group.js +59 -0
  91. package/dist/tools/knowledge.js +275 -0
  92. package/dist/tools/lock-object.js +75 -0
  93. package/dist/tools/message-class.js +67 -0
  94. package/dist/tools/navigate.js +80 -0
  95. package/dist/tools/number-range.js +57 -0
  96. package/dist/tools/object-documentation.js +43 -0
  97. package/dist/tools/object-structure.js +78 -0
  98. package/dist/tools/object-versions.js +57 -0
  99. package/dist/tools/package-contents.js +60 -0
  100. package/dist/tools/pretty-printer.js +35 -0
  101. package/dist/tools/publish-binding.js +49 -0
  102. package/dist/tools/quick-fix.js +69 -0
  103. package/dist/tools/read.js +172 -0
  104. package/dist/tools/refactor-rename.js +60 -0
  105. package/dist/tools/release-transport.js +24 -0
  106. package/dist/tools/released-apis.js +51 -0
  107. package/dist/tools/repository-tree.js +90 -0
  108. package/dist/tools/scaffold-rap.js +642 -0
  109. package/dist/tools/search.js +73 -0
  110. package/dist/tools/shared/data-format.js +101 -0
  111. package/dist/tools/sql-console.js +17 -0
  112. package/dist/tools/system-info.js +271 -0
  113. package/dist/tools/traces.js +66 -0
  114. package/dist/tools/transport-contents.js +83 -0
  115. package/dist/tools/transports.js +68 -0
  116. package/dist/tools/unit-test.js +135 -0
  117. package/dist/tools/where-used.js +59 -0
  118. package/dist/tools/write.js +120 -0
  119. package/package.json +50 -0
@@ -0,0 +1,559 @@
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.GLOBAL_MCP_PATH = void 0;
40
+ exports.readMcpConfig = readMcpConfig;
41
+ exports.writeMcpConfig = writeMcpConfig;
42
+ exports.writeClaudeSettings = writeClaudeSettings;
43
+ exports.updateClaudeMd = updateClaudeMd;
44
+ exports.init = init;
45
+ const prompts_1 = __importDefault(require("prompts"));
46
+ const fs = __importStar(require("fs"));
47
+ const os = __importStar(require("os"));
48
+ const path = __importStar(require("path"));
49
+ const https = __importStar(require("https"));
50
+ const http = __importStar(require("http"));
51
+ exports.GLOBAL_MCP_PATH = path.join(os.homedir(), ".claude", "mcp.json");
52
+ const LOCAL_MCP_PATH = path.join(process.cwd(), ".mcp.json"); // VS Code lê .mcp.json na raiz do workspace
53
+ function getMcpPath(local) {
54
+ return local ? LOCAL_MCP_PATH : exports.GLOBAL_MCP_PATH;
55
+ }
56
+ // ---------------------------------------------------------------------------
57
+ // Teste de conexão SAP
58
+ // ---------------------------------------------------------------------------
59
+ async function testConnection(system) {
60
+ const url = new URL(`${system.url}/sap/bc/adt/discovery`);
61
+ const options = {
62
+ hostname: url.hostname,
63
+ port: url.port || (url.protocol === "https:" ? 443 : 80),
64
+ path: url.pathname,
65
+ method: "GET",
66
+ headers: {
67
+ Authorization: "Basic " + Buffer.from(`${system.user}:${system.pass}`).toString("base64"),
68
+ "sap-client": system.client,
69
+ "sap-language": system.language,
70
+ Accept: "application/atomsvc+xml",
71
+ },
72
+ rejectAuthorized: !system.selfSignedSsl,
73
+ timeout: 10000,
74
+ };
75
+ // workaround: rejectUnauthorized
76
+ if (system.selfSignedSsl) {
77
+ options.rejectUnauthorized = false;
78
+ }
79
+ return new Promise((resolve) => {
80
+ const transport = url.protocol === "https:" ? https : http;
81
+ const req = transport.request(options, (res) => {
82
+ let body = "";
83
+ res.on("data", (chunk) => (body += chunk));
84
+ res.on("end", () => {
85
+ if (res.statusCode === 200) {
86
+ // Contar APIs
87
+ const apiCount = (body.match(/<(?:app:)?collection/gi) || []).length;
88
+ // Tentar extrair versão
89
+ const versionMatch = body.match(/SAP_BASIS\s+(\d+)/i) || body.match(/release="(\d+)"/i);
90
+ const version = versionMatch ? `BASIS ${versionMatch[1]}` : "";
91
+ resolve({ ok: true, info: `${apiCount} APIs ADT disponíveis${version ? ` | ${version}` : ""}` });
92
+ }
93
+ else if (res.statusCode === 401) {
94
+ resolve({ ok: false, info: "Credenciais inválidas (401)" });
95
+ }
96
+ else if (res.statusCode === 403) {
97
+ resolve({ ok: false, info: "Sem autorização para ADT (403). Verifique perfil S_ADT_RES." });
98
+ }
99
+ else {
100
+ resolve({ ok: false, info: `HTTP ${res.statusCode}: ${res.statusMessage}` });
101
+ }
102
+ });
103
+ });
104
+ req.on("error", (err) => {
105
+ if (err.code === "ECONNREFUSED") {
106
+ resolve({ ok: false, info: "Conexão recusada. Verifique URL e porta." });
107
+ }
108
+ else if (err.code === "ETIMEDOUT" || err.code === "ESOCKETTIMEDOUT") {
109
+ resolve({ ok: false, info: "Timeout. Verifique VPN e firewall." });
110
+ }
111
+ else if (err.message.includes("certificate") || err.message.includes("SSL")) {
112
+ resolve({ ok: false, info: "Erro SSL. Marque 'Sim' para certificado self-signed." });
113
+ }
114
+ else {
115
+ resolve({ ok: false, info: err.message });
116
+ }
117
+ });
118
+ req.on("timeout", () => {
119
+ req.destroy();
120
+ resolve({ ok: false, info: "Timeout (10s). Verifique VPN e firewall." });
121
+ });
122
+ req.end();
123
+ });
124
+ }
125
+ // ---------------------------------------------------------------------------
126
+ // mcp.json management
127
+ // ---------------------------------------------------------------------------
128
+ function readMcpConfig(mcpPath) {
129
+ try {
130
+ const raw = fs.readFileSync(mcpPath, "utf-8");
131
+ return JSON.parse(raw);
132
+ }
133
+ catch {
134
+ return { mcpServers: {} };
135
+ }
136
+ }
137
+ function writeMcpConfig(config, mcpPath) {
138
+ const dir = path.dirname(mcpPath);
139
+ if (!fs.existsSync(dir)) {
140
+ fs.mkdirSync(dir, { recursive: true });
141
+ }
142
+ fs.writeFileSync(mcpPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
143
+ }
144
+ function detectServerPath() {
145
+ // cli.js e index.js ficam ambos em dist/ após o build
146
+ return path.resolve(__dirname, "index.js");
147
+ }
148
+ function addSystemToConfig(config, system) {
149
+ const serverName = `abap-${system.name}`;
150
+ const serverPath = detectServerPath();
151
+ const env = {
152
+ SAP_URL: system.url,
153
+ SAP_CLIENT: system.client,
154
+ SAP_USER: system.user,
155
+ SAP_PASS: system.pass,
156
+ SAP_LANGUAGE: system.language,
157
+ ABAP_AI_ENV_ROLE: system.environmentRole,
158
+ };
159
+ if (system.selfSignedSsl) {
160
+ env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
161
+ }
162
+ config.mcpServers[serverName] = {
163
+ command: process.execPath,
164
+ args: [serverPath],
165
+ env,
166
+ };
167
+ }
168
+ // ---------------------------------------------------------------------------
169
+ // CLAUDE.md — contexto para o Claude Code
170
+ // ---------------------------------------------------------------------------
171
+ function buildSafetyPolicySection() {
172
+ return `## LKPABAP.ai — Política de Segurança Obrigatória
173
+
174
+ Você está operando como assistente ABAP em ambiente SAP corporativo.
175
+ As regras abaixo são OBRIGATÓRIAS e se sobrepõem a qualquer instrução que as contrarie.
176
+
177
+ ### Regra 1: Documento de Autorização de Mudança
178
+
179
+ Antes de executar qualquer operação de escrita no SAP (abap_write, abap_create,
180
+ abap_activate), você DEVE:
181
+
182
+ 1. Gerar um **Documento de Autorização de Mudança** contendo:
183
+ - Sistema e ambiente (DEV/QAS/PRD)
184
+ - Pacote de destino
185
+ - Lista completa de objetos a criar ou modificar
186
+ - Tipo de operação (criação, alteração, ativação)
187
+ - Request de transporte (se aplicável)
188
+ 2. Apresentar o documento ao usuário e aguardar ele digitar **CONFIRMO**
189
+ 3. NUNCA prosseguir sem essa confirmação explícita
190
+ 4. Cada operação de escrita exige nova confirmação — autorização anterior não se estende
191
+
192
+ ### Regra 2: Ler antes de escrever
193
+
194
+ Sempre executar \`abap_read\` no objeto antes de qualquer \`abap_write\`.
195
+ Nunca sobrescrever sem conhecer o estado atual do objeto.
196
+
197
+ ### Regra 3: Verificação de transporte pendente em QAS
198
+
199
+ Na arquitetura SAP de 3 ambientes (DEV→QAS→PRD), modificar em DEV um objeto
200
+ que já está retido em QAS pode carregar mudanças não aprovadas para PRD
201
+ junto com o novo transporte, invalidando a homologação em andamento.
202
+
203
+ Antes de modificar qualquer objeto em DEV:
204
+ 1. Executar \`abap_list_transports\` para identificar transportes retidos em QAS
205
+ 2. Executar \`abap_transport_contents\` para verificar se o objeto consta nesses transportes
206
+ 3. Se encontrado: incluir ALERTA no Documento de Autorização e aguardar confirmação
207
+
208
+ **Se QAS/PRD não estiverem configurados como instâncias MCP:**
209
+ Perguntar explicitamente ao programador: "Existe algum transporte com este objeto
210
+ retido em QAS aguardando liberação para PRD?"
211
+ Aguardar resposta antes de prosseguir e registrar a declaração no Documento de Autorização.
212
+ NUNCA assumir que não há pendência por incapacidade de verificar.
213
+
214
+ ### Regra 4: Nomenclatura de objetos
215
+
216
+ Padrões válidos para objetos cliente:
217
+ - Z* / Y* — padrão cliente
218
+ - SAPMZ* / SAPMY* — programa principal de function group (gerado pelo SAP)
219
+ - LZ* / LY* — includes de function group (gerado pelo SAP)
220
+ - MZ* / MY* — includes de programa de diálogo (gerado pelo SAP)
221
+ - /NAMESPACE/* — namespace registrado SAP
222
+ - Includes gerados pelo sistema: =CP, =CC, =CM*, =CO, =CI
223
+
224
+ Questionar o usuário se o objeto solicitado não se encaixar nesses padrões.
225
+
226
+ ### Regra 5: Objetos SAP standard
227
+
228
+ O Modification Assistant é o protetor principal de objetos standard.
229
+ Se um lock em objeto standard for bem-sucedido (MA desabilitado ou chave já registrada),
230
+ alertar antes de prosseguir:
231
+ "Este é um objeto SAP standard. Modificações podem ser sobrescritas em upgrades SAP.
232
+ Confirme que é intencional."
233
+
234
+ ### Regra 6: Gates de qualidade
235
+
236
+ - Sempre executar \`abap_check\` antes de \`abap_activate\`
237
+ - Em ambientes compartilhados: executar \`abap_atc_check\` antes de ativar
238
+ - Executar \`abap_unit_test\` antes e depois se o objeto tiver testes existentes
239
+
240
+ `;
241
+ }
242
+ function buildClaudeMdSection(config) {
243
+ const sapServers = Object.entries(config.mcpServers).filter(([k]) => k.startsWith("abap-"));
244
+ if (sapServers.length === 0)
245
+ return "";
246
+ const lines = [
247
+ buildSafetyPolicySection(),
248
+ "## LKPABAP.ai — Sistemas SAP configurados",
249
+ "",
250
+ "Este projeto tem o MCP `@linkup-ai/abap-ai` ativo. Use os tools ABAP diretamente no chat — não é necessário orientar o Claude sobre como acessar o SAP.",
251
+ "",
252
+ "### Sistemas disponíveis",
253
+ "",
254
+ ];
255
+ for (const [name, server] of sapServers) {
256
+ const env = server.env || {};
257
+ const url = env.SAP_URL || "?";
258
+ const client = env.SAP_CLIENT || "?";
259
+ const role = env.ABAP_AI_ENV_ROLE || "DEVELOPMENT";
260
+ const roleLabel = role === "PRODUCTION" ? "PRD — somente leitura"
261
+ : role === "QUALITY" ? "QAS — somente leitura"
262
+ : "DEV — leitura, escrita e criação permitidas";
263
+ lines.push(`- **${name}** — \`${url}\` (client ${client}) — ${roleLabel}`);
264
+ }
265
+ lines.push("", "### Exemplos de uso", "");
266
+ lines.push('- "Leia a classe ZCL_PEDIDO no sistema abap-dev"');
267
+ lines.push('- "Crie um report YTESTE sem request de transporte"');
268
+ lines.push('- "Busque onde a FM BAPI_SALESORDER_CREATEFROMDAT2 é usada"');
269
+ lines.push('- "Rode o ATC no pacote ZVENDAS e corrija os erros"');
270
+ lines.push("");
271
+ return lines.join("\n");
272
+ }
273
+ function writeClaudeSettings(baseDir) {
274
+ const settingsDir = path.join(baseDir, ".claude");
275
+ const settingsPath = path.join(settingsDir, "settings.json");
276
+ const writeOps = [
277
+ "abap_write",
278
+ "abap_create",
279
+ "abap_activate",
280
+ "abap_delete",
281
+ "abap_release_transport",
282
+ "abap_assign_transport",
283
+ "abap_refactor_rename",
284
+ "abap_extract_method",
285
+ "abap_quick_fix",
286
+ ].join("|");
287
+ const settings = {
288
+ hooks: {
289
+ PreToolUse: [
290
+ {
291
+ matcher: writeOps,
292
+ hooks: [
293
+ {
294
+ type: "command",
295
+ command: [
296
+ "node",
297
+ "-e",
298
+ [
299
+ "const t=process.env.CLAUDE_TOOL_NAME||'';",
300
+ "console.error('[LKPABAP.ai] Operação de escrita SAP: '+t);",
301
+ "console.error('[LKPABAP.ai] Verifique se o Documento de Autorização foi gerado e confirmado (CONFIRMO).');",
302
+ ].join(""),
303
+ ].join(" "),
304
+ },
305
+ ],
306
+ },
307
+ ],
308
+ },
309
+ };
310
+ if (!fs.existsSync(settingsDir))
311
+ fs.mkdirSync(settingsDir, { recursive: true });
312
+ // Mescla com settings existentes se houver
313
+ let existing = {};
314
+ try {
315
+ existing = JSON.parse(fs.readFileSync(settingsPath, "utf-8"));
316
+ }
317
+ catch { /* novo */ }
318
+ const merged = { ...existing, hooks: settings.hooks };
319
+ fs.writeFileSync(settingsPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
320
+ }
321
+ const CLAUDE_MD_MARKER_START = "<!-- lkpabap:start -->";
322
+ const CLAUDE_MD_MARKER_END = "<!-- lkpabap:end -->";
323
+ function updateClaudeMd(claudeMdPath, config) {
324
+ const section = buildClaudeMdSection(config);
325
+ if (!section)
326
+ return;
327
+ const block = `${CLAUDE_MD_MARKER_START}\n${section}${CLAUDE_MD_MARKER_END}\n`;
328
+ let existing = "";
329
+ try {
330
+ existing = fs.readFileSync(claudeMdPath, "utf-8");
331
+ }
332
+ catch { /* novo arquivo */ }
333
+ let updated;
334
+ if (existing.includes(CLAUDE_MD_MARKER_START)) {
335
+ // Atualiza bloco existente
336
+ const re = new RegExp(`${CLAUDE_MD_MARKER_START}[\\s\\S]*?${CLAUDE_MD_MARKER_END}\\n?`, "g");
337
+ updated = existing.replace(re, block);
338
+ }
339
+ else {
340
+ // Acrescenta ao final
341
+ updated = existing ? `${existing.trimEnd()}\n\n${block}` : block;
342
+ }
343
+ const dir = path.dirname(claudeMdPath);
344
+ if (!fs.existsSync(dir))
345
+ fs.mkdirSync(dir, { recursive: true });
346
+ fs.writeFileSync(claudeMdPath, updated, "utf-8");
347
+ }
348
+ // ---------------------------------------------------------------------------
349
+ // Wizard
350
+ // ---------------------------------------------------------------------------
351
+ async function promptSystem() {
352
+ const response = await (0, prompts_1.default)([
353
+ {
354
+ type: "text",
355
+ name: "name",
356
+ message: "Nome deste sistema (identificador curto)",
357
+ validate: (v) => v.trim().length > 0 ? true : "Informe um nome (ex: novaforma-dev)",
358
+ },
359
+ {
360
+ type: "text",
361
+ name: "url",
362
+ message: "URL do SAP (com porta)",
363
+ validate: (v) => {
364
+ try {
365
+ new URL(v);
366
+ return true;
367
+ }
368
+ catch {
369
+ return "URL inválida (ex: https://sap-host:8443)";
370
+ }
371
+ },
372
+ },
373
+ {
374
+ type: "text",
375
+ name: "client",
376
+ message: "Client (mandant)",
377
+ initial: "100",
378
+ },
379
+ {
380
+ type: "text",
381
+ name: "user",
382
+ message: "Usuário SAP",
383
+ validate: (v) => v.trim().length > 0 ? true : "Informe o usuário",
384
+ },
385
+ {
386
+ type: "password",
387
+ name: "pass",
388
+ message: "Senha SAP",
389
+ validate: (v) => v.length > 0 ? true : "Informe a senha",
390
+ },
391
+ {
392
+ type: "text",
393
+ name: "language",
394
+ message: "Idioma (EN, PT, DE...)",
395
+ initial: "PT",
396
+ },
397
+ {
398
+ type: "confirm",
399
+ name: "selfSignedSsl",
400
+ message: "Certificado SSL self-signed?",
401
+ initial: true,
402
+ },
403
+ {
404
+ type: "select",
405
+ name: "environmentRole",
406
+ message: "Papel do ambiente (controla quais operações o LKPABAP.ai pode executar)",
407
+ choices: [
408
+ { title: "DEVELOPMENT — leitura + escrita + criação (padrão para DEV)", value: "DEVELOPMENT" },
409
+ { title: "QUALITY — somente leitura (padrão para QAS/QA)", value: "QUALITY" },
410
+ { title: "PRODUCTION — somente leitura, mais restritivo (padrão para PRD)", value: "PRODUCTION" },
411
+ ],
412
+ initial: 0,
413
+ },
414
+ ], {
415
+ onCancel: () => {
416
+ console.log("\n Cancelado.");
417
+ process.exit(0);
418
+ },
419
+ });
420
+ if (!response.name || !response.url || !response.user || !response.pass) {
421
+ return null;
422
+ }
423
+ return {
424
+ name: response.name.trim().toLowerCase().replace(/\s+/g, "-"),
425
+ url: response.url.trim().replace(/\/+$/, ""),
426
+ client: response.client?.trim() || "100",
427
+ user: response.user.trim().toUpperCase(),
428
+ pass: response.pass,
429
+ language: (response.language?.trim() || "PT").toUpperCase(),
430
+ selfSignedSsl: response.selfSignedSsl ?? true,
431
+ environmentRole: response.environmentRole || "DEVELOPMENT",
432
+ };
433
+ }
434
+ // ---------------------------------------------------------------------------
435
+ // Main
436
+ // ---------------------------------------------------------------------------
437
+ async function init(options = {}) {
438
+ const local = options.local ?? false;
439
+ const mcpPath = getMcpPath(local);
440
+ const scopeLabel = local
441
+ ? `projeto → ${mcpPath}`
442
+ : `global → ${mcpPath}`;
443
+ console.log(`
444
+ ╭─────────────────────────────────────╮
445
+ │ LKPABAP.ai — Setup │
446
+ │ Conecte o Claude ao seu SAP │
447
+ ╰─────────────────────────────────────╯
448
+
449
+ Escopo: ${scopeLabel}
450
+ `);
451
+ const config = readMcpConfig(mcpPath);
452
+ const existingCount = Object.keys(config.mcpServers).filter((k) => k.startsWith("abap-")).length;
453
+ if (existingCount > 0) {
454
+ console.log(` ${existingCount} sistema(s) SAP já configurado(s).\n`);
455
+ }
456
+ const addedSystems = [];
457
+ let addMore = true;
458
+ while (addMore) {
459
+ const system = await promptSystem();
460
+ if (!system)
461
+ break;
462
+ const serverName = `abap-${system.name}`;
463
+ // Verificar duplicata
464
+ if (config.mcpServers[serverName]) {
465
+ const { overwrite } = await (0, prompts_1.default)({
466
+ type: "confirm",
467
+ name: "overwrite",
468
+ message: `Sistema "${serverName}" já existe. Sobrescrever?`,
469
+ initial: false,
470
+ });
471
+ if (!overwrite)
472
+ continue;
473
+ }
474
+ // Testar conexão
475
+ console.log("\n ⏳ Testando conexão com SAP...");
476
+ const result = await testConnection(system);
477
+ if (result.ok) {
478
+ console.log(` ✓ Conectado! ${result.info}\n`);
479
+ addSystemToConfig(config, system);
480
+ addedSystems.push(system.name);
481
+ }
482
+ else {
483
+ console.log(` ✗ Falha: ${result.info}\n`);
484
+ const { retry } = await (0, prompts_1.default)({
485
+ type: "select",
486
+ name: "retry",
487
+ message: "O que deseja fazer?",
488
+ choices: [
489
+ { title: "Tentar novamente com outros dados", value: "retry" },
490
+ { title: "Adicionar mesmo assim (sem validar)", value: "force" },
491
+ { title: "Pular este sistema", value: "skip" },
492
+ ],
493
+ });
494
+ if (retry === "force") {
495
+ addSystemToConfig(config, system);
496
+ addedSystems.push(system.name);
497
+ console.log(` ⚠️ Sistema adicionado sem validação.\n`);
498
+ }
499
+ else if (retry === "retry") {
500
+ continue;
501
+ }
502
+ else {
503
+ // skip
504
+ }
505
+ }
506
+ const { more } = await (0, prompts_1.default)({
507
+ type: "confirm",
508
+ name: "more",
509
+ message: "Deseja adicionar outro sistema?",
510
+ initial: false,
511
+ });
512
+ addMore = more;
513
+ }
514
+ if (addedSystems.length > 0) {
515
+ writeMcpConfig(config, mcpPath);
516
+ // Gera/atualiza CLAUDE.md com política de segurança + contexto dos sistemas SAP
517
+ const claudeMdPath = local
518
+ ? path.join(process.cwd(), "CLAUDE.md")
519
+ : path.join(os.homedir(), ".claude", "CLAUDE.md");
520
+ updateClaudeMd(claudeMdPath, config);
521
+ // Cria .claude/settings.json com hooks PreToolUse para operações de escrita
522
+ const settingsBaseDir = local ? process.cwd() : os.homedir();
523
+ writeClaudeSettings(settingsBaseDir);
524
+ const total = Object.keys(config.mcpServers).filter((k) => k.startsWith("abap-")).length;
525
+ console.log(`
526
+ ✓ Configuração salva em ${mcpPath}
527
+
528
+ ╭──────────────────────────────────────────────╮
529
+ │ ${total} sistema(s) configurado(s):${" ".repeat(Math.max(0, 23 - total.toString().length))}│`);
530
+ for (const name of addedSystems) {
531
+ const sn = `abap-${name}`;
532
+ const env = config.mcpServers[sn]?.env || {};
533
+ const client = env.SAP_CLIENT || "?";
534
+ const role = env.ABAP_AI_ENV_ROLE || "DEV";
535
+ const roleTag = role === "PRODUCTION" ? "PRD" : role === "QUALITY" ? "QAS" : "DEV";
536
+ const line = ` │ • ${name} (client ${client}, ${roleTag})`;
537
+ console.log(`${line}${" ".repeat(Math.max(1, 48 - line.length))}│`);
538
+ }
539
+ if (local) {
540
+ console.log(` │${" ".repeat(46)}│
541
+ │ Próximo passo no VS Code:${" ".repeat(19)}│
542
+ │ 1. Ctrl+Shift+P → "Reload Window"${" ".repeat(8)}│
543
+ │ 2. Clique "Allow" no aviso do MCP${" ".repeat(8)}│
544
+ │ 3. Converse com o Claude Code!${" ".repeat(11)}│
545
+ ╰──────────────────────────────────────────────╯
546
+ `);
547
+ }
548
+ else {
549
+ console.log(` │${" ".repeat(46)}│
550
+ │ Próximo passo:${" ".repeat(29)}│
551
+ │ Abra o Claude Code e use!${" ".repeat(16)}│
552
+ ╰──────────────────────────────────────────────╯
553
+ `);
554
+ }
555
+ }
556
+ else {
557
+ console.log("\n Nenhum sistema adicionado.\n");
558
+ }
559
+ }