abapgit-agent 1.5.0 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/README.md +1 -0
  2. package/abap/guidelines/00_index.md +36 -0
  3. package/abap/guidelines/01_sql.md +88 -0
  4. package/abap/guidelines/02_exceptions.md +176 -0
  5. package/abap/guidelines/03_testing.md +269 -0
  6. package/abap/guidelines/04_cds.md +136 -0
  7. package/abap/guidelines/05_classes.md +58 -0
  8. package/abap/guidelines/06_objects.md +110 -0
  9. package/abap/guidelines/07_json.md +24 -0
  10. package/abap/guidelines/08_abapgit.md +222 -0
  11. package/abap/guidelines/09_unit_testable_code.md +568 -0
  12. package/bin/abapgit-agent +513 -38
  13. package/bin/abgagt +24 -0
  14. package/package.json +8 -2
  15. package/src/abap-client.js +65 -2
  16. package/src/agent.js +57 -3
  17. package/src/config.js +1 -1
  18. package/src/ref-search.js +1037 -0
  19. package/.abapGitAgent.example +0 -11
  20. package/.github/workflows/release.yml +0 -60
  21. package/API.md +0 -710
  22. package/CLAUDE.md +0 -1058
  23. package/CLAUDE_MEM.md +0 -88
  24. package/ERROR_HANDLING.md +0 -30
  25. package/INSTALL.md +0 -155
  26. package/RELEASE_NOTES.md +0 -143
  27. package/abap/CLAUDE.md +0 -1010
  28. package/abap/copilot-instructions.md +0 -79
  29. package/abap/package.devc.xml +0 -10
  30. package/abap/zcl_abgagt_agent.clas.abap +0 -420
  31. package/abap/zcl_abgagt_agent.clas.xml +0 -15
  32. package/abap/zcl_abgagt_cmd_factory.clas.abap +0 -48
  33. package/abap/zcl_abgagt_cmd_factory.clas.xml +0 -15
  34. package/abap/zcl_abgagt_command_create.clas.abap +0 -95
  35. package/abap/zcl_abgagt_command_create.clas.xml +0 -15
  36. package/abap/zcl_abgagt_command_import.clas.abap +0 -138
  37. package/abap/zcl_abgagt_command_import.clas.xml +0 -15
  38. package/abap/zcl_abgagt_command_inspect.clas.abap +0 -456
  39. package/abap/zcl_abgagt_command_inspect.clas.testclasses.abap +0 -121
  40. package/abap/zcl_abgagt_command_inspect.clas.xml +0 -16
  41. package/abap/zcl_abgagt_command_preview.clas.abap +0 -386
  42. package/abap/zcl_abgagt_command_preview.clas.xml +0 -15
  43. package/abap/zcl_abgagt_command_pull.clas.abap +0 -80
  44. package/abap/zcl_abgagt_command_pull.clas.testclasses.abap +0 -87
  45. package/abap/zcl_abgagt_command_pull.clas.xml +0 -16
  46. package/abap/zcl_abgagt_command_tree.clas.abap +0 -237
  47. package/abap/zcl_abgagt_command_tree.clas.xml +0 -15
  48. package/abap/zcl_abgagt_command_unit.clas.abap +0 -297
  49. package/abap/zcl_abgagt_command_unit.clas.xml +0 -15
  50. package/abap/zcl_abgagt_command_view.clas.abap +0 -240
  51. package/abap/zcl_abgagt_command_view.clas.xml +0 -15
  52. package/abap/zcl_abgagt_resource_create.clas.abap +0 -71
  53. package/abap/zcl_abgagt_resource_create.clas.xml +0 -15
  54. package/abap/zcl_abgagt_resource_health.clas.abap +0 -25
  55. package/abap/zcl_abgagt_resource_health.clas.xml +0 -15
  56. package/abap/zcl_abgagt_resource_import.clas.abap +0 -66
  57. package/abap/zcl_abgagt_resource_import.clas.xml +0 -15
  58. package/abap/zcl_abgagt_resource_inspect.clas.abap +0 -63
  59. package/abap/zcl_abgagt_resource_inspect.clas.xml +0 -15
  60. package/abap/zcl_abgagt_resource_preview.clas.abap +0 -67
  61. package/abap/zcl_abgagt_resource_preview.clas.xml +0 -15
  62. package/abap/zcl_abgagt_resource_pull.clas.abap +0 -71
  63. package/abap/zcl_abgagt_resource_pull.clas.xml +0 -15
  64. package/abap/zcl_abgagt_resource_tree.clas.abap +0 -70
  65. package/abap/zcl_abgagt_resource_tree.clas.xml +0 -15
  66. package/abap/zcl_abgagt_resource_unit.clas.abap +0 -64
  67. package/abap/zcl_abgagt_resource_unit.clas.xml +0 -15
  68. package/abap/zcl_abgagt_resource_view.clas.abap +0 -68
  69. package/abap/zcl_abgagt_resource_view.clas.xml +0 -15
  70. package/abap/zcl_abgagt_rest_handler.clas.abap +0 -32
  71. package/abap/zcl_abgagt_rest_handler.clas.xml +0 -15
  72. package/abap/zcl_abgagt_util.clas.abap +0 -93
  73. package/abap/zcl_abgagt_util.clas.testclasses.abap +0 -84
  74. package/abap/zcl_abgagt_util.clas.xml +0 -16
  75. package/abap/zcl_abgagt_viewer_clas.clas.abap +0 -58
  76. package/abap/zcl_abgagt_viewer_clas.clas.xml +0 -15
  77. package/abap/zcl_abgagt_viewer_ddls.clas.abap +0 -83
  78. package/abap/zcl_abgagt_viewer_ddls.clas.xml +0 -15
  79. package/abap/zcl_abgagt_viewer_dtel.clas.abap +0 -98
  80. package/abap/zcl_abgagt_viewer_dtel.clas.xml +0 -15
  81. package/abap/zcl_abgagt_viewer_factory.clas.abap +0 -41
  82. package/abap/zcl_abgagt_viewer_factory.clas.xml +0 -15
  83. package/abap/zcl_abgagt_viewer_intf.clas.abap +0 -58
  84. package/abap/zcl_abgagt_viewer_intf.clas.xml +0 -15
  85. package/abap/zcl_abgagt_viewer_stru.clas.abap +0 -59
  86. package/abap/zcl_abgagt_viewer_stru.clas.xml +0 -15
  87. package/abap/zcl_abgagt_viewer_tabl.clas.abap +0 -59
  88. package/abap/zcl_abgagt_viewer_tabl.clas.xml +0 -15
  89. package/abap/zcl_abgagt_viewer_ttyp.clas.abap +0 -93
  90. package/abap/zcl_abgagt_viewer_ttyp.clas.xml +0 -15
  91. package/abap/zif_abgagt_agent.intf.abap +0 -53
  92. package/abap/zif_abgagt_agent.intf.xml +0 -15
  93. package/abap/zif_abgagt_cmd_factory.intf.abap +0 -7
  94. package/abap/zif_abgagt_cmd_factory.intf.xml +0 -15
  95. package/abap/zif_abgagt_command.intf.abap +0 -26
  96. package/abap/zif_abgagt_command.intf.xml +0 -15
  97. package/abap/zif_abgagt_util.intf.abap +0 -28
  98. package/abap/zif_abgagt_util.intf.xml +0 -15
  99. package/abap/zif_abgagt_viewer.intf.abap +0 -12
  100. package/abap/zif_abgagt_viewer.intf.xml +0 -15
  101. package/docs/commands.md +0 -142
  102. package/docs/create-command.md +0 -129
  103. package/docs/health-command.md +0 -89
  104. package/docs/import-command.md +0 -195
  105. package/docs/init-command.md +0 -189
  106. package/docs/inspect-command.md +0 -169
  107. package/docs/list-command.md +0 -289
  108. package/docs/preview-command.md +0 -528
  109. package/docs/pull-command.md +0 -202
  110. package/docs/status-command.md +0 -68
  111. package/docs/tree-command.md +0 -303
  112. package/docs/unit-command.md +0 -167
  113. package/docs/view-command.md +0 -501
  114. package/img/claude.png +0 -0
  115. package/scripts/claude-integration.js +0 -351
  116. package/scripts/release.js +0 -298
  117. package/scripts/release.sh +0 -60
  118. package/scripts/test-integration.js +0 -139
  119. package/scripts/unrelease.js +0 -277
package/bin/abgagt ADDED
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+ // abgagt - Short alias for abapgit-agent
3
+ // Usage: abgagt <command> [options]
4
+ //
5
+ // This is a wrapper script that forwards all arguments to abapgit-agent
6
+ //
7
+ // Examples:
8
+ // abgagt pull
9
+ // abgagt ref "CORRESPONDING"
10
+ // abgagt inspect --files zcl_my_class.clas.abap
11
+
12
+ const path = require('path');
13
+ const { spawn } = require('child_process');
14
+
15
+ const agentPath = path.join(__dirname, 'abapgit-agent');
16
+ const args = process.argv.slice(2);
17
+
18
+ const child = spawn('node', [agentPath, ...args], {
19
+ stdio: 'inherit'
20
+ });
21
+
22
+ child.on('exit', (code) => {
23
+ process.exit(code);
24
+ });
package/package.json CHANGED
@@ -1,10 +1,16 @@
1
1
  {
2
2
  "name": "abapgit-agent",
3
- "version": "1.5.0",
3
+ "version": "1.6.1",
4
4
  "description": "ABAP Git Agent - Pull and activate ABAP code via abapGit from any git repository",
5
5
  "main": "src/index.js",
6
+ "files": [
7
+ "bin/",
8
+ "src/",
9
+ "abap/guidelines/"
10
+ ],
6
11
  "bin": {
7
- "abapgit-agent": "bin/abapgit-agent"
12
+ "abapgit-agent": "bin/abapgit-agent",
13
+ "abgagt": "bin/abgagt"
8
14
  },
9
15
  "scripts": {
10
16
  "start": "node src/server.js",
@@ -379,7 +379,7 @@ class ABAPClient {
379
379
  return await this.request('POST', '/tree', data, { csrfToken: this.csrfToken });
380
380
  }
381
381
 
382
- async preview(objects, type = null, limit = 10) {
382
+ async preview(objects, type = null, limit = 10, where = null, columns = null) {
383
383
  // Fetch CSRF token first
384
384
  await this.fetchCsrfToken();
385
385
 
@@ -392,10 +392,73 @@ class ABAPClient {
392
392
  data.type = type;
393
393
  }
394
394
 
395
- logger.info('Previewing data', { objects, type, limit: data.limit, service: 'abapgit-agent' });
395
+ if (where) {
396
+ // Convert ISO date format (YYYY-MM-DD) to ABAP DATS format (YYYYMMDD)
397
+ // This handles date literals in WHERE clauses like "FLDATE = '2024-10-24'"
398
+ data.where = this.convertDatesInWhereClause(where);
399
+ }
400
+
401
+ if (columns) {
402
+ data.columns = columns;
403
+ }
404
+
405
+ logger.info('Previewing data', { objects, type, limit: data.limit, where: data.where, service: 'abapgit-agent' });
396
406
 
397
407
  return await this.request('POST', '/preview', data, { csrfToken: this.csrfToken });
398
408
  }
409
+
410
+ /**
411
+ * Convert ISO date formats to ABAP DATS format in WHERE clause
412
+ * @param {string} whereClause - SQL WHERE clause
413
+ * @returns {string} - WHERE clause with dates converted to YYYYMMDD format
414
+ */
415
+ convertDatesInWhereClause(whereClause) {
416
+ if (!whereClause) return whereClause;
417
+
418
+ // Pattern to match ISO date format: 'YYYY-MM-DD'
419
+ // Uses negative lookbehind and lookahead to ensure we're matching complete dates
420
+ const isoDatePattern = /'\d{4}-\d{2}-\d{2}'/g;
421
+
422
+ return whereClause.replace(isoDatePattern, (match) => {
423
+ // Extract YYYY, MM, DD from 'YYYY-MM-DD'
424
+ const dateContent = match.slice(1, -1); // Remove quotes: YYYY-MM-DD
425
+ const [year, month, day] = dateContent.split('-');
426
+ // Return in ABAP format: 'YYYYMMDD'
427
+ return `'${year}${month}${day}'`;
428
+ });
429
+ }
430
+
431
+ /**
432
+ * List objects in an ABAP package
433
+ * @param {string} packageName - ABAP package name
434
+ * @param {string} type - Comma-separated object types to filter (optional, e.g., 'CLAS,INTF')
435
+ * @param {string} name - Name pattern to filter (optional)
436
+ * @param {number} limit - Maximum number of objects to return (default: 100, max: 1000)
437
+ * @param {number} offset - Offset for pagination (default: 0)
438
+ * @returns {object} List result with objects, by_type, and total
439
+ */
440
+ async list(packageName, type = null, name = null, limit = 100, offset = 0) {
441
+ // Fetch CSRF token first
442
+ await this.fetchCsrfToken();
443
+
444
+ const data = {
445
+ package: packageName,
446
+ limit: Math.min(Math.max(1, limit), 1000),
447
+ offset: Math.max(0, offset)
448
+ };
449
+
450
+ if (type) {
451
+ data.type = type;
452
+ }
453
+
454
+ if (name) {
455
+ data.name = name;
456
+ }
457
+
458
+ logger.info('Listing objects', { package: packageName, type, name, limit: data.limit, offset: data.offset, service: 'abapgit-agent' });
459
+
460
+ return await this.request('POST', '/list', data, { csrfToken: this.csrfToken });
461
+ }
399
462
  }
400
463
 
401
464
  // Singleton instance
package/src/agent.js CHANGED
@@ -192,11 +192,20 @@ class ABAPGitAgent {
192
192
  }
193
193
  }
194
194
 
195
- async preview(objects, type = null, limit = 10) {
196
- logger.info('Previewing data', { objects, type, limit });
195
+ /**
196
+ * Preview data from ABAP tables or CDS views
197
+ * @param {Array} objects - Array of table/view names
198
+ * @param {string} type - Object type (TABL, DDLS, etc.)
199
+ * @param {number} limit - Maximum rows to return
200
+ * @param {string} where - WHERE clause filter
201
+ * @param {Array} columns - Array of column names to display
202
+ * @returns {object} Preview result with rows, fields, and metadata
203
+ */
204
+ async preview(objects, type = null, limit = 10, where = null, columns = null) {
205
+ logger.info('Previewing data', { objects, type, limit, where, columns });
197
206
 
198
207
  try {
199
- const result = await this.abap.preview(objects, type, limit);
208
+ const result = await this.abap.preview(objects, type, limit, where, columns);
200
209
  return {
201
210
  success: result.SUCCESS === 'X' || result.success === 'X' || result.success === true,
202
211
  command: result.COMMAND || result.command || 'PREVIEW',
@@ -210,6 +219,51 @@ class ABAPGitAgent {
210
219
  throw new Error(`Preview command failed: ${error.message}`);
211
220
  }
212
221
  }
222
+
223
+ /**
224
+ * List objects in an ABAP package
225
+ * @param {string} packageName - ABAP package name
226
+ * @param {string} type - Comma-separated object types to filter (optional)
227
+ * @param {string} name - Name pattern to filter (optional)
228
+ * @param {number} limit - Maximum number of objects to return (default: 100)
229
+ * @param {number} offset - Offset for pagination (default: 0)
230
+ * @returns {object} List result with objects, by_type, total, and error
231
+ */
232
+ async list(packageName, type = null, name = null, limit = 100, offset = 0) {
233
+ logger.info('Listing objects', { package: packageName, type, name, limit, offset });
234
+
235
+ try {
236
+ const result = await this.abap.list(packageName, type, name, limit, offset);
237
+
238
+ // Normalize objects array to use lowercase keys
239
+ const rawObjects = result.OBJECTS || result.objects || [];
240
+ const normalizedObjects = rawObjects.map(obj => ({
241
+ type: obj.TYPE || obj.type,
242
+ name: obj.NAME || obj.name
243
+ }));
244
+
245
+ // Normalize by_type array to use lowercase keys
246
+ const rawByType = result.BY_TYPE || result.by_type || [];
247
+ const normalizedByType = rawByType.map(item => ({
248
+ type: item.TYPE || item.type,
249
+ count: item.COUNT || item.count || 0
250
+ }));
251
+
252
+ return {
253
+ success: result.SUCCESS === 'X' || result.success === 'X' || result.success === true,
254
+ command: result.COMMAND || result.command || 'LIST',
255
+ package: result.PACKAGE || result.package || packageName,
256
+ message: result.MESSAGE || result.message || '',
257
+ objects: normalizedObjects,
258
+ by_type: normalizedByType,
259
+ total: result.TOTAL || result.total || 0,
260
+ error: result.ERROR || result.error || null
261
+ };
262
+ } catch (error) {
263
+ logger.error('List command failed', { error: error.message });
264
+ throw new Error(`List command failed: ${error.message}`);
265
+ }
266
+ }
213
267
  }
214
268
 
215
269
  module.exports = {
package/src/config.js CHANGED
@@ -24,7 +24,7 @@ function loadConfig() {
24
24
  if (fs.existsSync(configPath)) {
25
25
  config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
26
26
  } else {
27
- // Load from environment variables
27
+ // Load from environment variables only when no config file exists
28
28
  config = {
29
29
  host: process.env.ABAP_HOST,
30
30
  sapport: parseInt(process.env.ABAP_PORT, 10) || 443,