abapgit-agent 1.7.1 → 1.8.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 (41) hide show
  1. package/.abapGitAgent.example +11 -0
  2. package/README.md +7 -7
  3. package/abap/.github/copilot-instructions.md +254 -0
  4. package/abap/CLAUDE.md +432 -0
  5. package/abap/guidelines/00_index.md +8 -0
  6. package/abap/guidelines/01_sql.md +8 -0
  7. package/abap/guidelines/02_exceptions.md +8 -0
  8. package/abap/guidelines/03_testing.md +8 -0
  9. package/abap/guidelines/04_cds.md +8 -0
  10. package/abap/guidelines/05_classes.md +8 -0
  11. package/abap/guidelines/06_objects.md +8 -0
  12. package/abap/guidelines/07_json.md +8 -0
  13. package/abap/guidelines/08_abapgit.md +8 -0
  14. package/abap/guidelines/09_unit_testable_code.md +8 -0
  15. package/bin/abapgit-agent +61 -2789
  16. package/package.json +25 -5
  17. package/src/agent.js +213 -20
  18. package/src/commands/create.js +102 -0
  19. package/src/commands/delete.js +72 -0
  20. package/src/commands/health.js +24 -0
  21. package/src/commands/help.js +111 -0
  22. package/src/commands/import.js +99 -0
  23. package/src/commands/init.js +321 -0
  24. package/src/commands/inspect.js +184 -0
  25. package/src/commands/list.js +143 -0
  26. package/src/commands/preview.js +277 -0
  27. package/src/commands/pull.js +278 -0
  28. package/src/commands/ref.js +96 -0
  29. package/src/commands/status.js +52 -0
  30. package/src/commands/syntax.js +290 -0
  31. package/src/commands/tree.js +209 -0
  32. package/src/commands/unit.js +133 -0
  33. package/src/commands/view.js +215 -0
  34. package/src/commands/where.js +138 -0
  35. package/src/config.js +11 -1
  36. package/src/utils/abap-http.js +347 -0
  37. package/src/{ref-search.js → utils/abap-reference.js} +119 -1
  38. package/src/utils/git-utils.js +58 -0
  39. package/src/utils/validators.js +72 -0
  40. package/src/utils/version-check.js +80 -0
  41. package/src/abap-client.js +0 -523
package/package.json CHANGED
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "name": "abapgit-agent",
3
- "version": "1.7.1",
3
+ "version": "1.8.0",
4
4
  "description": "ABAP Git Agent - Pull and activate ABAP code via abapGit from any git repository",
5
5
  "main": "src/index.js",
6
6
  "files": [
7
7
  "bin/",
8
8
  "src/",
9
- "abap/guidelines/"
9
+ "abap/guidelines/",
10
+ "abap/CLAUDE.md",
11
+ "abap/.github/copilot-instructions.md",
12
+ ".abapGitAgent.example"
10
13
  ],
11
14
  "bin": {
12
15
  "abapgit-agent": "bin/abapgit-agent",
@@ -16,10 +19,21 @@
16
19
  "start": "node src/server.js",
17
20
  "dev": "nodemon src/server.js",
18
21
  "test": "jest",
19
- "test:all": "node scripts/test-all.js",
22
+ "test:all": "node tests/run-all.js",
23
+ "test:unit": "jest",
20
24
  "test:jest": "jest",
21
- "test:aunit": "node scripts/test-all.js --aunit",
22
- "test:cmd": "node scripts/test-all.js --cmd",
25
+ "test:integration": "node tests/run-all.js --cmd",
26
+ "test:aunit": "node tests/run-all.js --aunit",
27
+ "test:cmd": "node tests/run-all.js --cmd",
28
+ "test:cmd:demo": "node tests/run-all.js --cmd --demo",
29
+ "test:cmd:syntax": "node tests/run-all.js --cmd --command=syntax",
30
+ "test:cmd:pull": "node tests/run-all.js --cmd --command=pull",
31
+ "test:cmd:inspect": "node tests/run-all.js --cmd --command=inspect",
32
+ "test:cmd:unit": "node tests/run-all.js --cmd --command=unit",
33
+ "test:cmd:view": "node tests/run-all.js --cmd --command=view",
34
+ "test:cmd:preview": "node tests/run-all.js --cmd --command=preview",
35
+ "test:cmd:tree": "node tests/run-all.js --cmd --command=tree",
36
+ "test:lifecycle": "node tests/run-all.js --lifecycle",
23
37
  "pull": "node bin/abapgit-agent",
24
38
  "release": "node scripts/release.js",
25
39
  "unrelease": "node scripts/unrelease.js"
@@ -39,5 +53,11 @@
39
53
  },
40
54
  "engines": {
41
55
  "node": ">=16.0.0"
56
+ },
57
+ "jest": {
58
+ "testMatch": [
59
+ "**/tests/unit/**/*.test.js"
60
+ ],
61
+ "testEnvironment": "node"
42
62
  }
43
63
  }
package/src/agent.js CHANGED
@@ -1,13 +1,16 @@
1
1
  /**
2
2
  * ABAP Git Agent - Main agent class
3
+ * Uses AbapHttp for all ABAP communication
3
4
  */
4
5
 
5
- const { getClient } = require('./abap-client');
6
+ const { AbapHttp } = require('./utils/abap-http');
7
+ const { getAbapConfig } = require('./config');
6
8
  const logger = require('./logger');
7
9
 
8
10
  class ABAPGitAgent {
9
11
  constructor() {
10
- this.abap = getClient();
12
+ this.config = getAbapConfig();
13
+ this.http = new AbapHttp(this.config);
11
14
  }
12
15
 
13
16
  /**
@@ -17,13 +20,31 @@ class ABAPGitAgent {
17
20
  * @param {string} username - Git username (optional)
18
21
  * @param {string} password - Git password/token (optional)
19
22
  * @param {Array} files - Specific files to pull (optional)
23
+ * @param {string} transportRequest - Transport request number (optional)
20
24
  * @returns {object} Pull result with success, job_id, message, error_detail
21
25
  */
22
- async pull(repoUrl, branch = 'main', username = null, password = null, files = null) {
23
- logger.info('Starting pull operation', { repoUrl, branch, username: !!username, files });
26
+ async pull(repoUrl, branch = 'main', username = null, password = null, files = null, transportRequest = null) {
27
+ logger.info('Starting pull operation', { repoUrl, branch, username: !!username, files, transportRequest });
24
28
 
25
29
  try {
26
- const result = await this.abap.pull(repoUrl, branch, username, password, files);
30
+ const csrfToken = await this.http.fetchCsrfToken();
31
+
32
+ const data = {
33
+ url: repoUrl,
34
+ branch: branch,
35
+ username: username || this.config.gitUsername,
36
+ password: password || this.config.gitPassword
37
+ };
38
+
39
+ if (files && files.length > 0) {
40
+ data.files = files;
41
+ }
42
+
43
+ if (transportRequest) {
44
+ data.transport_request = transportRequest;
45
+ }
46
+
47
+ const result = await this.http.post('/sap/bc/z_abapgit_agent/pull', data, { csrfToken });
27
48
 
28
49
  // Return the result directly from ABAP (handle uppercase keys from /UI2/CL_JSON)
29
50
  return {
@@ -49,7 +70,7 @@ class ABAPGitAgent {
49
70
  */
50
71
  async healthCheck() {
51
72
  try {
52
- const result = await this.abap.healthCheck();
73
+ const result = await this.http.get('/sap/bc/z_abapgit_agent/health');
53
74
  return {
54
75
  status: 'healthy',
55
76
  abap: 'connected',
@@ -65,7 +86,7 @@ class ABAPGitAgent {
65
86
  }
66
87
 
67
88
  /**
68
- * Check syntax of an ABAP object
89
+ * Check syntax of an ABAP object (legacy - not used by CLI)
69
90
  * @param {string} objectType - ABAP object type (e.g., 'CLAS', 'PROG', 'INTF')
70
91
  * @param {string} objectName - ABAP object name
71
92
  * @returns {object} Syntax check result with errors (if any)
@@ -74,7 +95,13 @@ class ABAPGitAgent {
74
95
  logger.info('Starting syntax check', { objectType, objectName });
75
96
 
76
97
  try {
77
- const result = await this.abap.syntaxCheck(objectType, objectName);
98
+ const csrfToken = await this.http.fetchCsrfToken();
99
+ const data = {
100
+ object_type: objectType,
101
+ object_name: objectName
102
+ };
103
+
104
+ const result = await this.http.post('/sap/bc/z_abapgit_agent/syntax-check', data, { csrfToken });
78
105
  return {
79
106
  success: result.SUCCESS === 'X' || result.success === 'X' || result.success === true,
80
107
  object_type: result.OBJECT_TYPE || result.object_type,
@@ -88,6 +115,51 @@ class ABAPGitAgent {
88
115
  }
89
116
  }
90
117
 
118
+ /**
119
+ * Check syntax of ABAP source code directly (without pull/activation)
120
+ * Supported types: CLAS, INTF, PROG
121
+ * @param {Array} objects - Array of {type, name, source, locals_def?, locals_imp?}
122
+ * @param {string} uccheck - Unicode check mode ('X' for Standard, '5' for Cloud)
123
+ * @returns {object} Syntax check results with success, results array
124
+ */
125
+ async syntaxCheckSource(objects, uccheck = 'X') {
126
+ logger.info('Starting source syntax check', { objectCount: objects.length, uccheck });
127
+
128
+ try {
129
+ const csrfToken = await this.http.fetchCsrfToken();
130
+ const data = {
131
+ objects: objects,
132
+ uccheck: uccheck
133
+ };
134
+
135
+ const result = await this.http.post('/sap/bc/z_abapgit_agent/syntax', data, { csrfToken });
136
+ const success = result.SUCCESS === 'X' || result.SUCCESS === true ||
137
+ result.success === 'X' || result.success === true;
138
+ const results = result.RESULTS || result.results || [];
139
+ const message = result.MESSAGE || result.message || '';
140
+
141
+ // Normalize results
142
+ const normalizedResults = results.map(r => ({
143
+ object_type: r.OBJECT_TYPE || r.object_type,
144
+ object_name: r.OBJECT_NAME || r.object_name,
145
+ success: r.SUCCESS === 'X' || r.SUCCESS === true || r.success === 'X' || r.success === true,
146
+ error_count: r.ERROR_COUNT || r.error_count || 0,
147
+ errors: r.ERRORS || r.errors || [],
148
+ warnings: r.WARNINGS || r.warnings || [],
149
+ message: r.MESSAGE || r.message || ''
150
+ }));
151
+
152
+ return {
153
+ success,
154
+ message,
155
+ results: normalizedResults
156
+ };
157
+ } catch (error) {
158
+ logger.error('Source syntax check failed', { error: error.message });
159
+ throw new Error(`Source syntax check failed: ${error.message}`);
160
+ }
161
+ }
162
+
91
163
  /**
92
164
  * Run unit tests for package or objects
93
165
  * @param {string} packageName - Package name to run tests for (optional)
@@ -98,7 +170,18 @@ class ABAPGitAgent {
98
170
  logger.info('Starting unit tests', { package: packageName, objects });
99
171
 
100
172
  try {
101
- const result = await this.abap.unitTest(packageName, objects);
173
+ const csrfToken = await this.http.fetchCsrfToken();
174
+ const data = {};
175
+
176
+ if (packageName) {
177
+ data.package = packageName;
178
+ }
179
+
180
+ if (objects && objects.length > 0) {
181
+ data.objects = objects;
182
+ }
183
+
184
+ const result = await this.http.post('/sap/bc/z_abapgit_agent/unit', data, { csrfToken });
102
185
  return {
103
186
  success: result.SUCCESS === 'X' || result.success === 'X' || result.success === true,
104
187
  test_count: result.TEST_COUNT || result.test_count || 0,
@@ -127,7 +210,26 @@ class ABAPGitAgent {
127
210
  logger.info('Creating repository', { repoUrl, packageName, branch });
128
211
 
129
212
  try {
130
- const result = await this.abap.create(repoUrl, packageName, branch, displayName, name, folderLogic);
213
+ const csrfToken = await this.http.fetchCsrfToken();
214
+ const data = {
215
+ url: repoUrl,
216
+ package: packageName,
217
+ branch: branch
218
+ };
219
+
220
+ if (displayName) {
221
+ data.display_name = displayName;
222
+ }
223
+
224
+ if (name) {
225
+ data.name = name;
226
+ }
227
+
228
+ if (folderLogic) {
229
+ data.folder_logic = folderLogic;
230
+ }
231
+
232
+ const result = await this.http.post('/sap/bc/z_abapgit_agent/create', data, { csrfToken });
131
233
  return {
132
234
  success: result.SUCCESS === 'X' || result.success === 'X' || result.success === true,
133
235
  repo_key: result.REPO_KEY || result.repo_key,
@@ -151,7 +253,16 @@ class ABAPGitAgent {
151
253
  logger.info('Starting import operation', { repoUrl, message });
152
254
 
153
255
  try {
154
- const result = await this.abap.import(repoUrl, message);
256
+ const csrfToken = await this.http.fetchCsrfToken();
257
+ const data = {
258
+ url: repoUrl
259
+ };
260
+
261
+ if (message) {
262
+ data.message = message;
263
+ }
264
+
265
+ const result = await this.http.post('/sap/bc/z_abapgit_agent/import', data, { csrfToken });
155
266
  return {
156
267
  success: result.SUCCESS === 'X' || result.success === 'X' || result.success === true,
157
268
  files_staged: result.FILES_STAGED || result.files_staged || 0,
@@ -176,7 +287,14 @@ class ABAPGitAgent {
176
287
  logger.info('Getting package tree', { package: packageName, depth, includeObjects });
177
288
 
178
289
  try {
179
- const result = await this.abap.tree(packageName, depth, includeObjects);
290
+ const csrfToken = await this.http.fetchCsrfToken();
291
+ const data = {
292
+ package: packageName,
293
+ depth: Math.min(Math.max(1, depth), 10),
294
+ include_objects: includeObjects
295
+ };
296
+
297
+ const result = await this.http.post('/sap/bc/z_abapgit_agent/tree', data, { csrfToken });
180
298
  return {
181
299
  success: result.SUCCESS === 'X' || result.success === 'X' || result.success === true,
182
300
  command: result.COMMAND || result.command || 'TREE',
@@ -197,21 +315,43 @@ class ABAPGitAgent {
197
315
  * @param {Array} objects - Array of table/view names
198
316
  * @param {string} type - Object type (TABL, DDLS, etc.)
199
317
  * @param {number} limit - Maximum rows to return
318
+ * @param {number} offset - Number of rows to skip
200
319
  * @param {string} where - WHERE clause filter
201
320
  * @param {Array} columns - Array of column names to display
202
321
  * @returns {object} Preview result with rows, fields, and metadata
203
322
  */
204
- async preview(objects, type = null, limit = 10, where = null, columns = null) {
205
- logger.info('Previewing data', { objects, type, limit, where, columns });
323
+ async preview(objects, type = null, limit = 100, offset = 0, where = null, columns = null) {
324
+ logger.info('Previewing data', { objects, type, limit, offset, where, columns });
206
325
 
207
326
  try {
208
- const result = await this.abap.preview(objects, type, limit, where, columns);
327
+ const csrfToken = await this.http.fetchCsrfToken();
328
+ const data = {
329
+ objects: objects,
330
+ limit: Math.min(Math.max(1, limit), 500),
331
+ offset: Math.max(0, offset)
332
+ };
333
+
334
+ if (type) {
335
+ data.type = type;
336
+ }
337
+
338
+ if (where) {
339
+ // Convert ISO date format (YYYY-MM-DD) to ABAP DATS format (YYYYMMDD)
340
+ data.where = this.convertDatesInWhereClause(where);
341
+ }
342
+
343
+ if (columns) {
344
+ data.columns = columns;
345
+ }
346
+
347
+ const result = await this.http.post('/sap/bc/z_abapgit_agent/preview', data, { csrfToken });
209
348
  return {
210
349
  success: result.SUCCESS === 'X' || result.success === 'X' || result.success === true,
211
350
  command: result.COMMAND || result.command || 'PREVIEW',
212
351
  message: result.MESSAGE || result.message || '',
213
352
  objects: result.OBJECTS || result.objects || [],
214
353
  summary: result.SUMMARY || result.summary || null,
354
+ pagination: result.PAGINATION || result.pagination || null,
215
355
  error: result.ERROR || result.error || null
216
356
  };
217
357
  } catch (error) {
@@ -220,6 +360,22 @@ class ABAPGitAgent {
220
360
  }
221
361
  }
222
362
 
363
+ /**
364
+ * Convert ISO date formats to ABAP DATS format in WHERE clause
365
+ * @param {string} whereClause - SQL WHERE clause
366
+ * @returns {string} - WHERE clause with dates converted to YYYYMMDD format
367
+ */
368
+ convertDatesInWhereClause(whereClause) {
369
+ if (!whereClause) return whereClause;
370
+
371
+ const isoDatePattern = /'\\d{4}-\\d{2}-\\d{2}'/g;
372
+ return whereClause.replace(isoDatePattern, (match) => {
373
+ const dateContent = match.slice(1, -1);
374
+ const [year, month, day] = dateContent.split('-');
375
+ return `'${year}${month}${day}'`;
376
+ });
377
+ }
378
+
223
379
  /**
224
380
  * List objects in an ABAP package
225
381
  * @param {string} packageName - ABAP package name
@@ -233,7 +389,22 @@ class ABAPGitAgent {
233
389
  logger.info('Listing objects', { package: packageName, type, name, limit, offset });
234
390
 
235
391
  try {
236
- const result = await this.abap.list(packageName, type, name, limit, offset);
392
+ const csrfToken = await this.http.fetchCsrfToken();
393
+ const data = {
394
+ package: packageName,
395
+ limit: Math.min(Math.max(1, limit), 1000),
396
+ offset: Math.max(0, offset)
397
+ };
398
+
399
+ if (type) {
400
+ data.type = type;
401
+ }
402
+
403
+ if (name) {
404
+ data.name = name;
405
+ }
406
+
407
+ const result = await this.http.post('/sap/bc/z_abapgit_agent/list', data, { csrfToken });
237
408
 
238
409
  // Normalize objects array to use lowercase keys
239
410
  const rawObjects = result.OBJECTS || result.objects || [];
@@ -275,7 +446,16 @@ class ABAPGitAgent {
275
446
  logger.info('Viewing objects', { objects, type });
276
447
 
277
448
  try {
278
- const result = await this.abap.view(objects, type);
449
+ const csrfToken = await this.http.fetchCsrfToken();
450
+ const data = {
451
+ objects: objects
452
+ };
453
+
454
+ if (type) {
455
+ data.type = type;
456
+ }
457
+
458
+ const result = await this.http.post('/sap/bc/z_abapgit_agent/view', data, { csrfToken });
279
459
  return {
280
460
  success: result.SUCCESS === 'X' || result.success === 'X' || result.success === true,
281
461
  command: result.COMMAND || result.command || 'VIEW',
@@ -293,18 +473,31 @@ class ABAPGitAgent {
293
473
  * @param {Array} objects - Array of object names to search
294
474
  * @param {string} type - Object type (optional)
295
475
  * @param {number} limit - Maximum results (default: 100, max: 500)
476
+ * @param {number} offset - Number of results to skip (default: 0)
296
477
  * @returns {object} Where-used result with found objects
297
478
  */
298
- async where(objects, type = null, limit = 100) {
299
- logger.info('Finding where-used', { objects, type, limit });
479
+ async where(objects, type = null, limit = 100, offset = 0) {
480
+ logger.info('Finding where-used', { objects, type, limit, offset });
300
481
 
301
482
  try {
302
- const result = await this.abap.where(objects, type, limit);
483
+ const csrfToken = await this.http.fetchCsrfToken();
484
+ const data = {
485
+ objects: objects,
486
+ limit: Math.min(Math.max(1, limit), 500),
487
+ offset: Math.max(0, offset)
488
+ };
489
+
490
+ if (type) {
491
+ data.type = type;
492
+ }
493
+
494
+ const result = await this.http.post('/sap/bc/z_abapgit_agent/where-used', data, { csrfToken });
303
495
  return {
304
496
  success: result.SUCCESS === 'X' || result.success === 'X' || result.success === true,
305
497
  command: result.COMMAND || result.command || 'WHERE',
306
498
  objects: result.OBJECTS || result.objects || [],
307
499
  message: result.MESSAGE || result.message || '',
500
+ pagination: result.PAGINATION || result.pagination || null,
308
501
  error: result.ERROR || result.error || null
309
502
  };
310
503
  } catch (error) {
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Create command - Create abapGit online repository in ABAP system
3
+ */
4
+
5
+ module.exports = {
6
+ name: 'create',
7
+ description: 'Create abapGit online repository in ABAP system',
8
+ requiresAbapConfig: true,
9
+ requiresVersionCheck: true,
10
+
11
+ async execute(args, context) {
12
+ const { loadConfig, gitUtils, AbapHttp } = context;
13
+
14
+ // Show help if requested
15
+ const helpIndex = args.findIndex(a => a === '--help' || a === '-h');
16
+ if (helpIndex !== -1) {
17
+ console.log(`
18
+ Usage:
19
+ abapgit-agent create
20
+
21
+ Description:
22
+ Create abapGit online repository in ABAP system.
23
+ Auto-detects URL from git remote and package from .abapGitAgent.
24
+
25
+ Prerequisites:
26
+ - Run "abapgit-agent init" first
27
+ - Edit .abapGitAgent with credentials (host, user, password)
28
+
29
+ Examples:
30
+ abapgit-agent create # Create repo in ABAP
31
+ `);
32
+ return;
33
+ }
34
+
35
+ // Get parameters from config
36
+ const config = loadConfig();
37
+ const repoUrl = gitUtils.getRemoteUrl();
38
+
39
+ if (!repoUrl) {
40
+ console.error('Error: No git remote configured. Please configure a remote origin.');
41
+ process.exit(1);
42
+ }
43
+
44
+ if (!config.package) {
45
+ console.error('Error: Package not configured. Run "abapgit-agent init" first or set package in .abapGitAgent.');
46
+ process.exit(1);
47
+ }
48
+
49
+ const branch = gitUtils.getBranch();
50
+
51
+ // Extract repo name from git URL
52
+ const repoName = repoUrl.split('/').pop().replace('.git', '');
53
+
54
+ console.log(`\nšŸš€ Creating online repository`);
55
+ console.log(` URL: ${repoUrl}`);
56
+ console.log(` Package: ${config.package}`);
57
+ console.log(` Folder: ${config.folder || '/src/'}`);
58
+ console.log(` Name: ${repoName}`);
59
+ console.log(` Branch: ${branch}`);
60
+
61
+ const http = new AbapHttp(config);
62
+ const csrfToken = await http.fetchCsrfToken();
63
+
64
+ const data = {
65
+ url: repoUrl,
66
+ package: config.package,
67
+ name: repoName,
68
+ branch: branch,
69
+ folder: config.folder || '/src/'
70
+ };
71
+
72
+ if (config.gitUsername) {
73
+ data.username = config.gitUsername;
74
+ }
75
+
76
+ if (config.gitPassword) {
77
+ data.password = config.gitPassword;
78
+ }
79
+
80
+ const result = await http.post('/sap/bc/z_abapgit_agent/create', data, { csrfToken });
81
+
82
+ console.log('\n');
83
+
84
+ // Handle uppercase keys from ABAP
85
+ const success = result.SUCCESS || result.success;
86
+ const repoKey = result.REPO_KEY || result.repo_key;
87
+ const createdRepoName = result.REPO_NAME || result.repo_name;
88
+ const message = result.MESSAGE || result.message;
89
+ const error = result.ERROR || result.error;
90
+
91
+ if (success === 'X' || success === true) {
92
+ console.log(`āœ… Repository created successfully!`);
93
+ console.log(` URL: ${repoUrl}`);
94
+ console.log(` Package: ${config.package}`);
95
+ console.log(` Name: ${createdRepoName || repoName}`);
96
+ } else {
97
+ console.log(`āŒ Failed to create repository`);
98
+ console.log(` Error: ${error || message || 'Unknown error'}`);
99
+ process.exit(1);
100
+ }
101
+ }
102
+ };
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Delete command - Delete abapGit online repository from ABAP system
3
+ */
4
+
5
+ module.exports = {
6
+ name: 'delete',
7
+ description: 'Delete abapGit online repository from ABAP system',
8
+ requiresAbapConfig: true,
9
+ requiresVersionCheck: true,
10
+
11
+ async execute(args, context) {
12
+ const { loadConfig, gitUtils, AbapHttp } = context;
13
+
14
+ // Show help if requested
15
+ const helpIndex = args.findIndex(a => a === '--help' || a === '-h');
16
+ if (helpIndex !== -1) {
17
+ console.log(`
18
+ Usage:
19
+ abapgit-agent delete
20
+
21
+ Description:
22
+ Delete abapGit online repository from ABAP system.
23
+ Auto-detects URL from git remote of current directory.
24
+
25
+ Prerequisites:
26
+ - Run "abapgit-agent create" first
27
+
28
+ Examples:
29
+ abapgit-agent delete # Delete repo for current git remote
30
+ `);
31
+ return;
32
+ }
33
+
34
+ // Get URL from current git remote
35
+ const config = loadConfig();
36
+ const repoUrl = gitUtils.getRemoteUrl();
37
+
38
+ if (!repoUrl) {
39
+ console.error('Error: No git remote configured. Please configure a remote origin.');
40
+ process.exit(1);
41
+ }
42
+
43
+ console.log(`\nšŸ—‘ļø Deleting online repository`);
44
+ console.log(` URL: ${repoUrl}`);
45
+
46
+ const http = new AbapHttp(config);
47
+ const csrfToken = await http.fetchCsrfToken();
48
+
49
+ const data = {
50
+ url: repoUrl
51
+ };
52
+
53
+ const result = await http.post('/sap/bc/z_abapgit_agent/delete', data, { csrfToken });
54
+
55
+ console.log('\n');
56
+
57
+ // Handle uppercase keys from ABAP
58
+ const success = result.SUCCESS || result.success;
59
+ const repoKey = result.REPO_KEY || result.repo_key;
60
+ const message = result.MESSAGE || result.message;
61
+ const error = result.ERROR || result.error;
62
+
63
+ if (success === 'X' || success === true) {
64
+ console.log(`āœ… Repository deleted successfully!`);
65
+ console.log(` Key: ${repoKey}`);
66
+ } else {
67
+ console.log(`āŒ Failed to delete repository`);
68
+ console.log(` Error: ${error || message || 'Unknown error'}`);
69
+ process.exit(1);
70
+ }
71
+ }
72
+ };
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Health command - Check ABAP REST API health
3
+ */
4
+
5
+ module.exports = {
6
+ name: 'health',
7
+ description: 'Check if ABAP REST API is healthy',
8
+ requiresAbapConfig: true,
9
+ requiresVersionCheck: false,
10
+
11
+ async execute(args, context) {
12
+ const { config, AbapHttp } = context;
13
+
14
+ try {
15
+ const http = new AbapHttp(config);
16
+ const result = await http.get('/sap/bc/z_abapgit_agent/health');
17
+ console.log(JSON.stringify(result, null, 2));
18
+ return result;
19
+ } catch (error) {
20
+ console.error(`Health check failed: ${error.message}`);
21
+ process.exit(1);
22
+ }
23
+ }
24
+ };