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.
- package/README.md +1 -0
- package/abap/guidelines/00_index.md +36 -0
- package/abap/guidelines/01_sql.md +88 -0
- package/abap/guidelines/02_exceptions.md +176 -0
- package/abap/guidelines/03_testing.md +269 -0
- package/abap/guidelines/04_cds.md +136 -0
- package/abap/guidelines/05_classes.md +58 -0
- package/abap/guidelines/06_objects.md +110 -0
- package/abap/guidelines/07_json.md +24 -0
- package/abap/guidelines/08_abapgit.md +222 -0
- package/abap/guidelines/09_unit_testable_code.md +568 -0
- package/bin/abapgit-agent +513 -38
- package/bin/abgagt +24 -0
- package/package.json +8 -2
- package/src/abap-client.js +65 -2
- package/src/agent.js +57 -3
- package/src/config.js +1 -1
- package/src/ref-search.js +1037 -0
- package/.abapGitAgent.example +0 -11
- package/.github/workflows/release.yml +0 -60
- package/API.md +0 -710
- package/CLAUDE.md +0 -1058
- package/CLAUDE_MEM.md +0 -88
- package/ERROR_HANDLING.md +0 -30
- package/INSTALL.md +0 -155
- package/RELEASE_NOTES.md +0 -143
- package/abap/CLAUDE.md +0 -1010
- package/abap/copilot-instructions.md +0 -79
- package/abap/package.devc.xml +0 -10
- package/abap/zcl_abgagt_agent.clas.abap +0 -420
- package/abap/zcl_abgagt_agent.clas.xml +0 -15
- package/abap/zcl_abgagt_cmd_factory.clas.abap +0 -48
- package/abap/zcl_abgagt_cmd_factory.clas.xml +0 -15
- package/abap/zcl_abgagt_command_create.clas.abap +0 -95
- package/abap/zcl_abgagt_command_create.clas.xml +0 -15
- package/abap/zcl_abgagt_command_import.clas.abap +0 -138
- package/abap/zcl_abgagt_command_import.clas.xml +0 -15
- package/abap/zcl_abgagt_command_inspect.clas.abap +0 -456
- package/abap/zcl_abgagt_command_inspect.clas.testclasses.abap +0 -121
- package/abap/zcl_abgagt_command_inspect.clas.xml +0 -16
- package/abap/zcl_abgagt_command_preview.clas.abap +0 -386
- package/abap/zcl_abgagt_command_preview.clas.xml +0 -15
- package/abap/zcl_abgagt_command_pull.clas.abap +0 -80
- package/abap/zcl_abgagt_command_pull.clas.testclasses.abap +0 -87
- package/abap/zcl_abgagt_command_pull.clas.xml +0 -16
- package/abap/zcl_abgagt_command_tree.clas.abap +0 -237
- package/abap/zcl_abgagt_command_tree.clas.xml +0 -15
- package/abap/zcl_abgagt_command_unit.clas.abap +0 -297
- package/abap/zcl_abgagt_command_unit.clas.xml +0 -15
- package/abap/zcl_abgagt_command_view.clas.abap +0 -240
- package/abap/zcl_abgagt_command_view.clas.xml +0 -15
- package/abap/zcl_abgagt_resource_create.clas.abap +0 -71
- package/abap/zcl_abgagt_resource_create.clas.xml +0 -15
- package/abap/zcl_abgagt_resource_health.clas.abap +0 -25
- package/abap/zcl_abgagt_resource_health.clas.xml +0 -15
- package/abap/zcl_abgagt_resource_import.clas.abap +0 -66
- package/abap/zcl_abgagt_resource_import.clas.xml +0 -15
- package/abap/zcl_abgagt_resource_inspect.clas.abap +0 -63
- package/abap/zcl_abgagt_resource_inspect.clas.xml +0 -15
- package/abap/zcl_abgagt_resource_preview.clas.abap +0 -67
- package/abap/zcl_abgagt_resource_preview.clas.xml +0 -15
- package/abap/zcl_abgagt_resource_pull.clas.abap +0 -71
- package/abap/zcl_abgagt_resource_pull.clas.xml +0 -15
- package/abap/zcl_abgagt_resource_tree.clas.abap +0 -70
- package/abap/zcl_abgagt_resource_tree.clas.xml +0 -15
- package/abap/zcl_abgagt_resource_unit.clas.abap +0 -64
- package/abap/zcl_abgagt_resource_unit.clas.xml +0 -15
- package/abap/zcl_abgagt_resource_view.clas.abap +0 -68
- package/abap/zcl_abgagt_resource_view.clas.xml +0 -15
- package/abap/zcl_abgagt_rest_handler.clas.abap +0 -32
- package/abap/zcl_abgagt_rest_handler.clas.xml +0 -15
- package/abap/zcl_abgagt_util.clas.abap +0 -93
- package/abap/zcl_abgagt_util.clas.testclasses.abap +0 -84
- package/abap/zcl_abgagt_util.clas.xml +0 -16
- package/abap/zcl_abgagt_viewer_clas.clas.abap +0 -58
- package/abap/zcl_abgagt_viewer_clas.clas.xml +0 -15
- package/abap/zcl_abgagt_viewer_ddls.clas.abap +0 -83
- package/abap/zcl_abgagt_viewer_ddls.clas.xml +0 -15
- package/abap/zcl_abgagt_viewer_dtel.clas.abap +0 -98
- package/abap/zcl_abgagt_viewer_dtel.clas.xml +0 -15
- package/abap/zcl_abgagt_viewer_factory.clas.abap +0 -41
- package/abap/zcl_abgagt_viewer_factory.clas.xml +0 -15
- package/abap/zcl_abgagt_viewer_intf.clas.abap +0 -58
- package/abap/zcl_abgagt_viewer_intf.clas.xml +0 -15
- package/abap/zcl_abgagt_viewer_stru.clas.abap +0 -59
- package/abap/zcl_abgagt_viewer_stru.clas.xml +0 -15
- package/abap/zcl_abgagt_viewer_tabl.clas.abap +0 -59
- package/abap/zcl_abgagt_viewer_tabl.clas.xml +0 -15
- package/abap/zcl_abgagt_viewer_ttyp.clas.abap +0 -93
- package/abap/zcl_abgagt_viewer_ttyp.clas.xml +0 -15
- package/abap/zif_abgagt_agent.intf.abap +0 -53
- package/abap/zif_abgagt_agent.intf.xml +0 -15
- package/abap/zif_abgagt_cmd_factory.intf.abap +0 -7
- package/abap/zif_abgagt_cmd_factory.intf.xml +0 -15
- package/abap/zif_abgagt_command.intf.abap +0 -26
- package/abap/zif_abgagt_command.intf.xml +0 -15
- package/abap/zif_abgagt_util.intf.abap +0 -28
- package/abap/zif_abgagt_util.intf.xml +0 -15
- package/abap/zif_abgagt_viewer.intf.abap +0 -12
- package/abap/zif_abgagt_viewer.intf.xml +0 -15
- package/docs/commands.md +0 -142
- package/docs/create-command.md +0 -129
- package/docs/health-command.md +0 -89
- package/docs/import-command.md +0 -195
- package/docs/init-command.md +0 -189
- package/docs/inspect-command.md +0 -169
- package/docs/list-command.md +0 -289
- package/docs/preview-command.md +0 -528
- package/docs/pull-command.md +0 -202
- package/docs/status-command.md +0 -68
- package/docs/tree-command.md +0 -303
- package/docs/unit-command.md +0 -167
- package/docs/view-command.md +0 -501
- package/img/claude.png +0 -0
- package/scripts/claude-integration.js +0 -351
- package/scripts/release.js +0 -298
- package/scripts/release.sh +0 -60
- package/scripts/test-integration.js +0 -139
- package/scripts/unrelease.js +0 -277
package/bin/abapgit-agent
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
* ABAP Git Agent - CLI Tool
|
|
4
4
|
*
|
|
5
5
|
* Usage:
|
|
6
|
-
* abapgit-agent init --folder <folder> --package <package>
|
|
6
|
+
* abapgit-agent init --folder <folder> --package <package> # Initialize: copies config, CLAUDE.md, guidelines
|
|
7
|
+
* abapgit-agent init --update # Update existing files to latest version
|
|
7
8
|
* abapgit-agent create
|
|
8
9
|
* abapgit-agent import [--message <message>]
|
|
9
10
|
* abapgit-agent pull [--branch <branch>]
|
|
@@ -23,6 +24,27 @@ const TERM_WIDTH = getTermWidth();
|
|
|
23
24
|
|
|
24
25
|
const COOKIE_FILE = '.abapgit_agent_cookies.txt';
|
|
25
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Convert ISO date formats (YYYY-MM-DD) to ABAP DATS format (YYYYMMDD) in WHERE clause
|
|
29
|
+
* This allows users to use familiar ISO date formats while ensuring compatibility with ABAP SQL
|
|
30
|
+
* @param {string} whereClause - SQL WHERE clause
|
|
31
|
+
* @returns {string} - WHERE clause with dates converted to YYYYMMDD format
|
|
32
|
+
*/
|
|
33
|
+
function convertDatesInWhereClause(whereClause) {
|
|
34
|
+
if (!whereClause) return whereClause;
|
|
35
|
+
|
|
36
|
+
// Pattern to match ISO date format: 'YYYY-MM-DD'
|
|
37
|
+
const isoDatePattern = /'\d{4}-\d{2}-\d{2}'/g;
|
|
38
|
+
|
|
39
|
+
return whereClause.replace(isoDatePattern, (match) => {
|
|
40
|
+
// Extract YYYY, MM, DD from 'YYYY-MM-DD'
|
|
41
|
+
const dateContent = match.slice(1, -1); // Remove quotes: YYYY-MM-DD
|
|
42
|
+
const [year, month, day] = dateContent.split('-');
|
|
43
|
+
// Return in ABAP format: 'YYYYMMDD'
|
|
44
|
+
return `'${year}${month}${day}'`;
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
26
48
|
/**
|
|
27
49
|
* Get CLI version from package.json
|
|
28
50
|
*/
|
|
@@ -516,12 +538,14 @@ async function processInspectResult(res) {
|
|
|
516
538
|
const errorCount = res.ERROR_COUNT !== undefined ? res.ERROR_COUNT : (res.error_count || 0);
|
|
517
539
|
const errors = res.ERRORS !== undefined ? res.ERRORS : (res.errors || []);
|
|
518
540
|
const warnings = res.WARNINGS !== undefined ? res.WARNINGS : (res.warnings || []);
|
|
541
|
+
const infos = res.INFOS !== undefined ? res.INFOS : (res.infos || []);
|
|
519
542
|
|
|
520
|
-
if (errorCount > 0 || warnings.length > 0) {
|
|
543
|
+
if (errorCount > 0 || warnings.length > 0 || infos.length > 0) {
|
|
521
544
|
if (errorCount > 0) {
|
|
522
545
|
console.log(`❌ ${objectType} ${objectName} - Syntax check failed (${errorCount} error(s)):`);
|
|
523
546
|
} else {
|
|
524
|
-
|
|
547
|
+
const total = warnings.length + infos.length;
|
|
548
|
+
console.log(`⚠️ ${objectType} ${objectName} - Syntax check passed with warnings (${total}):`);
|
|
525
549
|
}
|
|
526
550
|
console.log('\nErrors:');
|
|
527
551
|
console.log('─'.repeat(60));
|
|
@@ -530,8 +554,16 @@ async function processInspectResult(res) {
|
|
|
530
554
|
const line = err.LINE || err.line || '?';
|
|
531
555
|
const column = err.COLUMN || err.column || '?';
|
|
532
556
|
const text = err.TEXT || err.text || 'Unknown error';
|
|
557
|
+
const methodName = err.METHOD_NAME || err.method_name;
|
|
558
|
+
const sobjname = err.SOBJNAME || err.sobjname;
|
|
533
559
|
|
|
560
|
+
if (methodName) {
|
|
561
|
+
console.log(` Method: ${methodName}`);
|
|
562
|
+
}
|
|
534
563
|
console.log(` Line ${line}, Column ${column}:`);
|
|
564
|
+
if (sobjname && sobjname.includes('====')) {
|
|
565
|
+
console.log(` Include: ${sobjname}`);
|
|
566
|
+
}
|
|
535
567
|
console.log(` ${text}`);
|
|
536
568
|
console.log('');
|
|
537
569
|
}
|
|
@@ -543,7 +575,38 @@ async function processInspectResult(res) {
|
|
|
543
575
|
for (const warn of warnings) {
|
|
544
576
|
const line = warn.LINE || warn.line || '?';
|
|
545
577
|
const text = warn.MESSAGE || warn.message || 'Unknown warning';
|
|
546
|
-
|
|
578
|
+
const methodName = warn.METHOD_NAME || warn.method_name;
|
|
579
|
+
const sobjname = warn.SOBJNAME || warn.sobjname;
|
|
580
|
+
|
|
581
|
+
if (methodName) {
|
|
582
|
+
console.log(` Method: ${methodName}`);
|
|
583
|
+
}
|
|
584
|
+
console.log(` Line ${line}:`);
|
|
585
|
+
if (sobjname && sobjname.includes('====')) {
|
|
586
|
+
console.log(` Include: ${sobjname}`);
|
|
587
|
+
}
|
|
588
|
+
console.log(` ${text}`);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
// Show infos if any
|
|
593
|
+
if (infos.length > 0) {
|
|
594
|
+
console.log('Info:');
|
|
595
|
+
console.log('─'.repeat(60));
|
|
596
|
+
for (const info of infos) {
|
|
597
|
+
const line = info.LINE || info.line || '?';
|
|
598
|
+
const text = info.MESSAGE || info.message || 'Unknown info';
|
|
599
|
+
const methodName = info.METHOD_NAME || info.method_name;
|
|
600
|
+
const sobjname = info.SOBJNAME || info.sobjname;
|
|
601
|
+
|
|
602
|
+
if (methodName) {
|
|
603
|
+
console.log(` Method: ${methodName}`);
|
|
604
|
+
}
|
|
605
|
+
console.log(` Line ${line}:`);
|
|
606
|
+
if (sobjname && sobjname.includes('====')) {
|
|
607
|
+
console.log(` Include: ${sobjname}`);
|
|
608
|
+
}
|
|
609
|
+
console.log(` ${text}`);
|
|
547
610
|
}
|
|
548
611
|
}
|
|
549
612
|
} else if (success === true || success === 'X') {
|
|
@@ -630,7 +693,7 @@ async function runUnitTests(options) {
|
|
|
630
693
|
/**
|
|
631
694
|
* Run unit test for a single file
|
|
632
695
|
*/
|
|
633
|
-
async function runUnitTestForFile(sourceFile, csrfToken, config) {
|
|
696
|
+
async function runUnitTestForFile(sourceFile, csrfToken, config, coverage = false) {
|
|
634
697
|
console.log(` Running unit test for: ${sourceFile}`);
|
|
635
698
|
|
|
636
699
|
try {
|
|
@@ -665,7 +728,8 @@ async function runUnitTestForFile(sourceFile, csrfToken, config) {
|
|
|
665
728
|
|
|
666
729
|
// Send files array to unit endpoint (ABAP expects string_table of file names)
|
|
667
730
|
const data = {
|
|
668
|
-
files: [sourceFile]
|
|
731
|
+
files: [sourceFile],
|
|
732
|
+
coverage: coverage
|
|
669
733
|
};
|
|
670
734
|
|
|
671
735
|
const result = await request('POST', '/sap/bc/z_abapgit_agent/unit', data, { csrfToken });
|
|
@@ -678,6 +742,9 @@ async function runUnitTestForFile(sourceFile, csrfToken, config) {
|
|
|
678
742
|
const message = result.MESSAGE || result.message || '';
|
|
679
743
|
const errors = result.ERRORS || result.errors || [];
|
|
680
744
|
|
|
745
|
+
// Handle coverage data
|
|
746
|
+
const coverageStats = result.COVERAGE_STATS || result.coverage_stats;
|
|
747
|
+
|
|
681
748
|
if (testCount === 0) {
|
|
682
749
|
console.log(` ➖ ${objName} - No unit tests`);
|
|
683
750
|
} else if (success === 'X' || success === true) {
|
|
@@ -688,6 +755,17 @@ async function runUnitTestForFile(sourceFile, csrfToken, config) {
|
|
|
688
755
|
|
|
689
756
|
console.log(` Tests: ${testCount} | Passed: ${passedCount} | Failed: ${failedCount}`);
|
|
690
757
|
|
|
758
|
+
// Display coverage if available
|
|
759
|
+
if (coverage && coverageStats) {
|
|
760
|
+
const totalLines = coverageStats.TOTAL_LINES || coverageStats.total_lines || 0;
|
|
761
|
+
const coveredLines = coverageStats.COVERED_LINES || coverageStats.covered_lines || 0;
|
|
762
|
+
const coverageRate = coverageStats.COVERAGE_RATE || coverageStats.coverage_rate || 0;
|
|
763
|
+
|
|
764
|
+
console.log(` 📊 Coverage: ${coverageRate}%`);
|
|
765
|
+
console.log(` Total Lines: ${totalLines}`);
|
|
766
|
+
console.log(` Covered Lines: ${coveredLines}`);
|
|
767
|
+
}
|
|
768
|
+
|
|
691
769
|
if (failedCount > 0 && errors.length > 0) {
|
|
692
770
|
for (const err of errors) {
|
|
693
771
|
const className = err.CLASS_NAME || err.class_name || '?';
|
|
@@ -706,11 +784,11 @@ async function runUnitTestForFile(sourceFile, csrfToken, config) {
|
|
|
706
784
|
/**
|
|
707
785
|
* Run tree command and return raw result
|
|
708
786
|
*/
|
|
709
|
-
async function runTreeCommand(packageName, depth,
|
|
787
|
+
async function runTreeCommand(packageName, depth, includeTypes, csrfToken, config) {
|
|
710
788
|
const data = {
|
|
711
789
|
package: packageName,
|
|
712
790
|
depth: depth,
|
|
713
|
-
include_objects:
|
|
791
|
+
include_objects: includeTypes
|
|
714
792
|
};
|
|
715
793
|
|
|
716
794
|
return await request('POST', '/sap/bc/z_abapgit_agent/tree', data, { csrfToken });
|
|
@@ -719,13 +797,13 @@ async function runTreeCommand(packageName, depth, includeObjects, csrfToken, con
|
|
|
719
797
|
/**
|
|
720
798
|
* Display tree output in human-readable format
|
|
721
799
|
*/
|
|
722
|
-
async function displayTreeOutput(packageName, depth,
|
|
800
|
+
async function displayTreeOutput(packageName, depth, includeTypes) {
|
|
723
801
|
const config = loadConfig();
|
|
724
802
|
const csrfToken = await fetchCsrfToken(config);
|
|
725
803
|
|
|
726
804
|
console.log(`\n Getting package tree for: ${packageName}`);
|
|
727
805
|
|
|
728
|
-
const result = await runTreeCommand(packageName, depth,
|
|
806
|
+
const result = await runTreeCommand(packageName, depth, includeTypes, csrfToken, config);
|
|
729
807
|
|
|
730
808
|
// Handle uppercase keys from ABAP
|
|
731
809
|
const success = result.SUCCESS || result.success;
|
|
@@ -765,7 +843,7 @@ async function displayTreeOutput(packageName, depth, includeObjects) {
|
|
|
765
843
|
console.log(` OBJECTS: ${totalObjects}`);
|
|
766
844
|
|
|
767
845
|
// Display object types if available
|
|
768
|
-
if (
|
|
846
|
+
if (includeTypes && objectTypes.length > 0) {
|
|
769
847
|
const typeStr = objectTypes.map(t => `${t.OBJECT || t.object}=${t.COUNT || t.count}`).join(' ');
|
|
770
848
|
console.log(` TYPES: ${typeStr}`);
|
|
771
849
|
}
|
|
@@ -1068,12 +1146,86 @@ async function pull(gitUrl, branch = 'main', files = null, transportRequest = nu
|
|
|
1068
1146
|
}
|
|
1069
1147
|
}
|
|
1070
1148
|
|
|
1149
|
+
/**
|
|
1150
|
+
* Copy a file if source exists (helper for init --update)
|
|
1151
|
+
* @param {string} srcPath - Source file path
|
|
1152
|
+
* @param {string} destPath - Destination file path
|
|
1153
|
+
* @param {string} label - Label for console output
|
|
1154
|
+
* @param {boolean} createParentDir - Whether to create parent directory
|
|
1155
|
+
* @returns {Promise<void>}
|
|
1156
|
+
*/
|
|
1157
|
+
async function copyFileIfExists(srcPath, destPath, label, createParentDir = false) {
|
|
1158
|
+
try {
|
|
1159
|
+
if (fs.existsSync(srcPath)) {
|
|
1160
|
+
if (createParentDir) {
|
|
1161
|
+
const parentDir = pathModule.dirname(destPath);
|
|
1162
|
+
if (!fs.existsSync(parentDir)) {
|
|
1163
|
+
fs.mkdirSync(parentDir, { recursive: true });
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
fs.copyFileSync(srcPath, destPath);
|
|
1167
|
+
console.log(`✅ Updated ${label}`);
|
|
1168
|
+
} else {
|
|
1169
|
+
console.log(`⚠️ ${label} not found in abapgit-agent`);
|
|
1170
|
+
}
|
|
1171
|
+
} catch (error) {
|
|
1172
|
+
console.error(`Error copying ${label}: ${error.message}`);
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
/**
|
|
1177
|
+
* Copy guidelines folder (helper for init --update)
|
|
1178
|
+
* @param {string} srcPath - Source folder path
|
|
1179
|
+
* @param {string} destPath - Destination folder path
|
|
1180
|
+
* @param {boolean} overwrite - Whether to overwrite existing files
|
|
1181
|
+
* @returns {Promise<void>}
|
|
1182
|
+
*/
|
|
1183
|
+
async function copyGuidelinesFolder(srcPath, destPath, overwrite = false) {
|
|
1184
|
+
try {
|
|
1185
|
+
if (fs.existsSync(srcPath)) {
|
|
1186
|
+
// Create destination directory if needed
|
|
1187
|
+
if (!fs.existsSync(destPath)) {
|
|
1188
|
+
fs.mkdirSync(destPath, { recursive: true });
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
const files = fs.readdirSync(srcPath);
|
|
1192
|
+
let copied = 0;
|
|
1193
|
+
|
|
1194
|
+
for (const file of files) {
|
|
1195
|
+
if (file.endsWith('.md')) {
|
|
1196
|
+
const srcFile = pathModule.join(srcPath, file);
|
|
1197
|
+
const destFile = pathModule.join(destPath, file);
|
|
1198
|
+
|
|
1199
|
+
// Skip if file exists and not overwriting
|
|
1200
|
+
if (fs.existsSync(destFile) && !overwrite) {
|
|
1201
|
+
continue;
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
fs.copyFileSync(srcFile, destFile);
|
|
1205
|
+
copied++;
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
if (copied > 0) {
|
|
1210
|
+
console.log(`✅ Updated guidelines/ (${copied} files)`);
|
|
1211
|
+
} else {
|
|
1212
|
+
console.log(`⚠️ No guideline files found`);
|
|
1213
|
+
}
|
|
1214
|
+
} else {
|
|
1215
|
+
console.log(`⚠️ guidelines folder not found in abapgit-agent`);
|
|
1216
|
+
}
|
|
1217
|
+
} catch (error) {
|
|
1218
|
+
console.error(`Error copying guidelines: ${error.message}`);
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1071
1222
|
/**
|
|
1072
1223
|
* Run init command - Initialize local configuration
|
|
1073
1224
|
*/
|
|
1074
1225
|
async function runInit(args) {
|
|
1075
1226
|
const folderArgIndex = args.indexOf('--folder');
|
|
1076
1227
|
const packageArgIndex = args.indexOf('--package');
|
|
1228
|
+
const updateMode = args.includes('--update');
|
|
1077
1229
|
|
|
1078
1230
|
// Get parameters
|
|
1079
1231
|
const folder = folderArgIndex !== -1 && folderArgIndex + 1 < args.length
|
|
@@ -1084,18 +1236,14 @@ async function runInit(args) {
|
|
|
1084
1236
|
? args[packageArgIndex + 1]
|
|
1085
1237
|
: null;
|
|
1086
1238
|
|
|
1087
|
-
// Validate package is required
|
|
1088
|
-
if (!packageName) {
|
|
1239
|
+
// Validate package is required for non-update mode
|
|
1240
|
+
if (!updateMode && !packageName) {
|
|
1089
1241
|
console.error('Error: --package is required');
|
|
1090
1242
|
console.error('Usage: abapgit-agent init --folder /src --package ZMY_PACKAGE');
|
|
1243
|
+
console.error(' abapgit-agent init --update # Update files to latest version');
|
|
1091
1244
|
process.exit(1);
|
|
1092
1245
|
}
|
|
1093
1246
|
|
|
1094
|
-
console.log(`\n🚀 Initializing abapGit Agent for local repository`);
|
|
1095
|
-
console.log(` Folder: ${folder}`);
|
|
1096
|
-
console.log(` Package: ${packageName}`);
|
|
1097
|
-
console.log('');
|
|
1098
|
-
|
|
1099
1247
|
// Check if current folder is git repo root
|
|
1100
1248
|
const gitDir = pathModule.join(process.cwd(), '.git');
|
|
1101
1249
|
if (!fs.existsSync(gitDir)) {
|
|
@@ -1104,6 +1252,53 @@ async function runInit(args) {
|
|
|
1104
1252
|
process.exit(1);
|
|
1105
1253
|
}
|
|
1106
1254
|
|
|
1255
|
+
// In update mode, just copy the files and return
|
|
1256
|
+
if (updateMode) {
|
|
1257
|
+
console.log(`\n🔄 Updating abapGit Agent files`);
|
|
1258
|
+
console.log('');
|
|
1259
|
+
|
|
1260
|
+
// Copy CLAUDE.md
|
|
1261
|
+
await copyFileIfExists(
|
|
1262
|
+
pathModule.join(__dirname, '..', 'abap', 'CLAUDE.md'),
|
|
1263
|
+
pathModule.join(process.cwd(), 'CLAUDE.md'),
|
|
1264
|
+
'CLAUDE.md'
|
|
1265
|
+
);
|
|
1266
|
+
|
|
1267
|
+
// Copy copilot-instructions.md
|
|
1268
|
+
await copyFileIfExists(
|
|
1269
|
+
pathModule.join(__dirname, '..', 'abap', '.github', 'copilot-instructions.md'),
|
|
1270
|
+
pathModule.join(process.cwd(), '.github', 'copilot-instructions.md'),
|
|
1271
|
+
'.github/copilot-instructions.md',
|
|
1272
|
+
true // create parent dir
|
|
1273
|
+
);
|
|
1274
|
+
|
|
1275
|
+
// Copy guidelines folder to project root
|
|
1276
|
+
await copyGuidelinesFolder(
|
|
1277
|
+
pathModule.join(__dirname, '..', 'abap', 'guidelines'),
|
|
1278
|
+
pathModule.join(process.cwd(), 'guidelines'),
|
|
1279
|
+
true // overwrite
|
|
1280
|
+
);
|
|
1281
|
+
|
|
1282
|
+
console.log(`
|
|
1283
|
+
📋 Update complete!
|
|
1284
|
+
Run 'abapgit-agent ref --list-topics' to see available topics.
|
|
1285
|
+
`);
|
|
1286
|
+
return;
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
// Validate package is required
|
|
1290
|
+
if (!packageName) {
|
|
1291
|
+
console.error('Error: --package is required');
|
|
1292
|
+
console.error('Usage: abapgit-agent init --folder /src --package ZMY_PACKAGE');
|
|
1293
|
+
console.error(' abapgit-agent init --update # Update files to latest version');
|
|
1294
|
+
process.exit(1);
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
console.log(`\n🚀 Initializing abapGit Agent for local repository`);
|
|
1298
|
+
console.log(` Folder: ${folder}`);
|
|
1299
|
+
console.log(` Package: ${packageName}`);
|
|
1300
|
+
console.log('');
|
|
1301
|
+
|
|
1107
1302
|
// Detect git remote URL
|
|
1108
1303
|
const gitUrl = getGitRemoteUrl();
|
|
1109
1304
|
if (!gitUrl) {
|
|
@@ -1188,7 +1383,7 @@ async function runInit(args) {
|
|
|
1188
1383
|
}
|
|
1189
1384
|
|
|
1190
1385
|
// Copy copilot-instructions.md for GitHub Copilot
|
|
1191
|
-
const copilotMdPath = pathModule.join(__dirname, '..', 'abap', 'copilot-instructions.md');
|
|
1386
|
+
const copilotMdPath = pathModule.join(__dirname, '..', 'abap', '.github', 'copilot-instructions.md');
|
|
1192
1387
|
const githubDir = pathModule.join(process.cwd(), '.github');
|
|
1193
1388
|
const localCopilotMdPath = pathModule.join(githubDir, 'copilot-instructions.md');
|
|
1194
1389
|
try {
|
|
@@ -1206,6 +1401,35 @@ async function runInit(args) {
|
|
|
1206
1401
|
console.error(`Error copying copilot-instructions.md: ${error.message}`);
|
|
1207
1402
|
}
|
|
1208
1403
|
|
|
1404
|
+
// Copy guidelines folder to project root
|
|
1405
|
+
const guidelinesSrcPath = pathModule.join(__dirname, '..', 'abap', 'guidelines');
|
|
1406
|
+
const guidelinesDestPath = pathModule.join(process.cwd(), 'guidelines');
|
|
1407
|
+
try {
|
|
1408
|
+
if (fs.existsSync(guidelinesSrcPath)) {
|
|
1409
|
+
if (!fs.existsSync(guidelinesDestPath)) {
|
|
1410
|
+
// Create guidelines directory
|
|
1411
|
+
fs.mkdirSync(guidelinesDestPath, { recursive: true });
|
|
1412
|
+
// Copy all files from guidelines folder
|
|
1413
|
+
const files = fs.readdirSync(guidelinesSrcPath);
|
|
1414
|
+
for (const file of files) {
|
|
1415
|
+
if (file.endsWith('.md')) {
|
|
1416
|
+
fs.copyFileSync(
|
|
1417
|
+
pathModule.join(guidelinesSrcPath, file),
|
|
1418
|
+
pathModule.join(guidelinesDestPath, file)
|
|
1419
|
+
);
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
console.log(`✅ Created guidelines/ (${files.filter(f => f.endsWith('.md')).length} files)`);
|
|
1423
|
+
} else {
|
|
1424
|
+
console.log(`⚠️ guidelines/ already exists, skipped`);
|
|
1425
|
+
}
|
|
1426
|
+
} else {
|
|
1427
|
+
console.log(`⚠️ guidelines folder not found in abap/ directory`);
|
|
1428
|
+
}
|
|
1429
|
+
} catch (error) {
|
|
1430
|
+
console.error(`Error copying guidelines: ${error.message}`);
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1209
1433
|
// Create folder
|
|
1210
1434
|
const folderPath = pathModule.join(process.cwd(), folder);
|
|
1211
1435
|
try {
|
|
@@ -1253,8 +1477,9 @@ async function main() {
|
|
|
1253
1477
|
const command = args[0];
|
|
1254
1478
|
|
|
1255
1479
|
// Check if ABAP integration is enabled for this repo
|
|
1256
|
-
// (skip for init, help commands)
|
|
1257
|
-
|
|
1480
|
+
// (skip for init, help, ref commands - these don't need ABAP connection)
|
|
1481
|
+
const noAbapRequired = ['init', 'help', '--help', '-h', 'ref'];
|
|
1482
|
+
if (command && !noAbapRequired.includes(command)) {
|
|
1258
1483
|
if (!isAbapIntegrationEnabled()) {
|
|
1259
1484
|
console.log(`
|
|
1260
1485
|
⚠️ ABAP Git Agent not configured for this repository.
|
|
@@ -1278,7 +1503,7 @@ To enable integration:
|
|
|
1278
1503
|
}
|
|
1279
1504
|
|
|
1280
1505
|
// Version compatibility check for commands that interact with ABAP
|
|
1281
|
-
const abapCommands = ['create', 'import', 'pull', 'inspect', 'unit', 'tree', 'view', 'preview'];
|
|
1506
|
+
const abapCommands = ['create', 'import', 'pull', 'inspect', 'unit', 'tree', 'view', 'preview', 'list'];
|
|
1282
1507
|
if (command && abapCommands.includes(command)) {
|
|
1283
1508
|
await checkVersionCompatibility();
|
|
1284
1509
|
}
|
|
@@ -1558,21 +1783,25 @@ Examples:
|
|
|
1558
1783
|
const filesArgIndex = args.indexOf('--files');
|
|
1559
1784
|
if (filesArgIndex === -1 || filesArgIndex + 1 >= args.length) {
|
|
1560
1785
|
console.error('Error: --files parameter required');
|
|
1561
|
-
console.error('Usage: abapgit-agent unit --files <file1>,<file2>,...');
|
|
1786
|
+
console.error('Usage: abapgit-agent unit --files <file1>,<file2>,... [--coverage]');
|
|
1562
1787
|
console.error('Example: abapgit-agent unit --files zcl_my_test.clas.abap');
|
|
1788
|
+
console.error('Example: abapgit-agent unit --files zcl_my_test.clas.abap --coverage');
|
|
1563
1789
|
process.exit(1);
|
|
1564
1790
|
}
|
|
1565
1791
|
|
|
1566
1792
|
const files = args[filesArgIndex + 1].split(',').map(f => f.trim());
|
|
1567
1793
|
|
|
1568
|
-
|
|
1794
|
+
// Check for coverage option
|
|
1795
|
+
const coverage = args.includes('--coverage');
|
|
1796
|
+
|
|
1797
|
+
console.log(`\n Running unit tests for ${files.length} file(s)${coverage ? ' (with coverage)' : ''}`);
|
|
1569
1798
|
console.log('');
|
|
1570
1799
|
|
|
1571
1800
|
const config = loadConfig();
|
|
1572
1801
|
const csrfToken = await fetchCsrfToken(config);
|
|
1573
1802
|
|
|
1574
1803
|
for (const sourceFile of files) {
|
|
1575
|
-
await runUnitTestForFile(sourceFile, csrfToken, config);
|
|
1804
|
+
await runUnitTestForFile(sourceFile, csrfToken, config, coverage);
|
|
1576
1805
|
}
|
|
1577
1806
|
break;
|
|
1578
1807
|
}
|
|
@@ -1581,7 +1810,7 @@ Examples:
|
|
|
1581
1810
|
const packageArgIndex = args.indexOf('--package');
|
|
1582
1811
|
if (packageArgIndex === -1) {
|
|
1583
1812
|
console.error('Error: --package parameter required');
|
|
1584
|
-
console.error('Usage: abapgit-agent tree --package <package> [--depth <n>] [--include-
|
|
1813
|
+
console.error('Usage: abapgit-agent tree --package <package> [--depth <n>] [--include-types] [--json]');
|
|
1585
1814
|
console.error('Example: abapgit-agent tree --package ZMY_PACKAGE');
|
|
1586
1815
|
process.exit(1);
|
|
1587
1816
|
}
|
|
@@ -1595,7 +1824,7 @@ Examples:
|
|
|
1595
1824
|
console.error(' or escape the $ character:');
|
|
1596
1825
|
console.error(' abapgit-agent tree --package \\$ZMY_PACKAGE');
|
|
1597
1826
|
console.error('');
|
|
1598
|
-
console.error('Usage: abapgit-agent tree --package <package> [--depth <n>] [--include-
|
|
1827
|
+
console.error('Usage: abapgit-agent tree --package <package> [--depth <n>] [--include-types] [--json]');
|
|
1599
1828
|
console.error('Example: abapgit-agent tree --package ZMY_PACKAGE');
|
|
1600
1829
|
process.exit(1);
|
|
1601
1830
|
}
|
|
@@ -1605,7 +1834,7 @@ Examples:
|
|
|
1605
1834
|
// Check for empty/whitespace-only package name
|
|
1606
1835
|
if (!packageName || packageName.trim() === '') {
|
|
1607
1836
|
console.error('Error: --package parameter cannot be empty');
|
|
1608
|
-
console.error('Usage: abapgit-agent tree --package <package> [--depth <n>] [--include-
|
|
1837
|
+
console.error('Usage: abapgit-agent tree --package <package> [--depth <n>] [--include-types] [--json]');
|
|
1609
1838
|
console.error('Example: abapgit-agent tree --package ZMY_PACKAGE');
|
|
1610
1839
|
process.exit(1);
|
|
1611
1840
|
}
|
|
@@ -1621,8 +1850,8 @@ Examples:
|
|
|
1621
1850
|
}
|
|
1622
1851
|
}
|
|
1623
1852
|
|
|
1624
|
-
// Optional include-objects
|
|
1625
|
-
const
|
|
1853
|
+
// Optional include-types parameter (--include-objects is deprecated alias)
|
|
1854
|
+
const includeTypes = args.includes('--include-types') || args.includes('--include-objects');
|
|
1626
1855
|
|
|
1627
1856
|
// Optional json parameter
|
|
1628
1857
|
const jsonOutput = args.includes('--json');
|
|
@@ -1630,10 +1859,141 @@ Examples:
|
|
|
1630
1859
|
if (jsonOutput) {
|
|
1631
1860
|
const config = loadConfig();
|
|
1632
1861
|
const csrfToken = await fetchCsrfToken(config);
|
|
1633
|
-
const result = await runTreeCommand(packageName, depth,
|
|
1862
|
+
const result = await runTreeCommand(packageName, depth, includeTypes, csrfToken, config);
|
|
1634
1863
|
console.log(JSON.stringify(result, null, 2));
|
|
1635
1864
|
} else {
|
|
1636
|
-
await displayTreeOutput(packageName, depth,
|
|
1865
|
+
await displayTreeOutput(packageName, depth, includeTypes);
|
|
1866
|
+
}
|
|
1867
|
+
break;
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1870
|
+
case 'list': {
|
|
1871
|
+
const packageArgIndex = args.indexOf('--package');
|
|
1872
|
+
if (packageArgIndex === -1) {
|
|
1873
|
+
console.error('Error: --package parameter required');
|
|
1874
|
+
console.error('Usage: abapgit-agent list --package <package> [--type <types>] [--name <pattern>] [--limit <n>] [--offset <n>] [--json]');
|
|
1875
|
+
console.error('Example: abapgit-agent list --package $ZMY_PACKAGE');
|
|
1876
|
+
console.error('Example: abapgit-agent list --package $ZMY_PACKAGE --type CLAS,INTF');
|
|
1877
|
+
process.exit(1);
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
// Check if package value is missing
|
|
1881
|
+
if (packageArgIndex + 1 >= args.length) {
|
|
1882
|
+
console.error('Error: --package parameter value is missing');
|
|
1883
|
+
process.exit(1);
|
|
1884
|
+
}
|
|
1885
|
+
|
|
1886
|
+
const packageName = args[packageArgIndex + 1];
|
|
1887
|
+
|
|
1888
|
+
// Validate package name
|
|
1889
|
+
if (!packageName || packageName.trim() === '') {
|
|
1890
|
+
console.error('Error: --package parameter cannot be empty');
|
|
1891
|
+
process.exit(1);
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1894
|
+
// Optional type parameter
|
|
1895
|
+
const typeArgIndex = args.indexOf('--type');
|
|
1896
|
+
const type = typeArgIndex !== -1 && typeArgIndex + 1 < args.length ? args[typeArgIndex + 1] : null;
|
|
1897
|
+
|
|
1898
|
+
// Optional name pattern
|
|
1899
|
+
const nameArgIndex = args.indexOf('--name');
|
|
1900
|
+
const name = nameArgIndex !== -1 && nameArgIndex + 1 < args.length ? args[nameArgIndex + 1] : null;
|
|
1901
|
+
|
|
1902
|
+
// Optional limit
|
|
1903
|
+
const limitArgIndex = args.indexOf('--limit');
|
|
1904
|
+
let limit = 100;
|
|
1905
|
+
if (limitArgIndex !== -1 && limitArgIndex + 1 < args.length) {
|
|
1906
|
+
limit = parseInt(args[limitArgIndex + 1], 10);
|
|
1907
|
+
if (isNaN(limit) || limit < 1) {
|
|
1908
|
+
console.error('Error: --limit must be a positive number');
|
|
1909
|
+
process.exit(1);
|
|
1910
|
+
}
|
|
1911
|
+
if (limit > 1000) {
|
|
1912
|
+
console.error('Error: --limit value too high (max: 1000)');
|
|
1913
|
+
process.exit(1);
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
|
|
1917
|
+
// Optional offset
|
|
1918
|
+
const offsetArgIndex = args.indexOf('--offset');
|
|
1919
|
+
let offset = 0;
|
|
1920
|
+
if (offsetArgIndex !== -1 && offsetArgIndex + 1 < args.length) {
|
|
1921
|
+
offset = parseInt(args[offsetArgIndex + 1], 10);
|
|
1922
|
+
if (isNaN(offset) || offset < 0) {
|
|
1923
|
+
console.error('Error: --offset must be a non-negative number');
|
|
1924
|
+
process.exit(1);
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1927
|
+
|
|
1928
|
+
// Optional json parameter
|
|
1929
|
+
const jsonOutput = args.includes('--json');
|
|
1930
|
+
|
|
1931
|
+
const config = loadConfig();
|
|
1932
|
+
const csrfToken = await fetchCsrfToken(config);
|
|
1933
|
+
|
|
1934
|
+
const data = {
|
|
1935
|
+
package: packageName,
|
|
1936
|
+
limit: limit,
|
|
1937
|
+
offset: offset
|
|
1938
|
+
};
|
|
1939
|
+
|
|
1940
|
+
if (type) {
|
|
1941
|
+
data.type = type;
|
|
1942
|
+
}
|
|
1943
|
+
|
|
1944
|
+
if (name) {
|
|
1945
|
+
data.name = name;
|
|
1946
|
+
}
|
|
1947
|
+
|
|
1948
|
+
const result = await request('POST', '/sap/bc/z_abapgit_agent/list', data, { csrfToken });
|
|
1949
|
+
|
|
1950
|
+
// Handle uppercase keys from ABAP
|
|
1951
|
+
const success = result.SUCCESS || result.success;
|
|
1952
|
+
const error = result.ERROR || result.error;
|
|
1953
|
+
const objects = result.OBJECTS || result.objects || [];
|
|
1954
|
+
const byType = result.BY_TYPE || result.by_type || [];
|
|
1955
|
+
const total = result.TOTAL || result.total || 0;
|
|
1956
|
+
|
|
1957
|
+
if (!success || error) {
|
|
1958
|
+
console.error(`\n Error: ${error || 'Failed to list objects'}`);
|
|
1959
|
+
process.exit(1);
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
if (jsonOutput) {
|
|
1963
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1964
|
+
} else {
|
|
1965
|
+
// Display human-readable output
|
|
1966
|
+
let title = `Objects in ${packageName}`;
|
|
1967
|
+
if (type) {
|
|
1968
|
+
title += ` (${type} only`;
|
|
1969
|
+
if (total !== objects.length) {
|
|
1970
|
+
title += `, Total: ${total}`;
|
|
1971
|
+
}
|
|
1972
|
+
title += ')';
|
|
1973
|
+
} else if (total !== objects.length) {
|
|
1974
|
+
title += ` (Total: ${total})`;
|
|
1975
|
+
}
|
|
1976
|
+
console.log(`\n${title}\n`);
|
|
1977
|
+
|
|
1978
|
+
// Group objects by type
|
|
1979
|
+
const objectsByType = {};
|
|
1980
|
+
for (const obj of objects) {
|
|
1981
|
+
const objType = (obj.TYPE || obj.type || '???').toUpperCase();
|
|
1982
|
+
if (!objectsByType[objType]) {
|
|
1983
|
+
objectsByType[objType] = [];
|
|
1984
|
+
}
|
|
1985
|
+
objectsByType[objType].push(obj.NAME || obj.name);
|
|
1986
|
+
}
|
|
1987
|
+
|
|
1988
|
+
// Display grouped objects
|
|
1989
|
+
for (const objType of Object.keys(objectsByType).sort()) {
|
|
1990
|
+
const objNames = objectsByType[objType];
|
|
1991
|
+
console.log(` ${objType} (${objNames.length})`);
|
|
1992
|
+
for (const objName of objNames) {
|
|
1993
|
+
console.log(` ${objName}`);
|
|
1994
|
+
}
|
|
1995
|
+
console.log('');
|
|
1996
|
+
}
|
|
1637
1997
|
}
|
|
1638
1998
|
break;
|
|
1639
1999
|
}
|
|
@@ -1881,7 +2241,7 @@ Examples:
|
|
|
1881
2241
|
}
|
|
1882
2242
|
|
|
1883
2243
|
if (where) {
|
|
1884
|
-
data.where = where;
|
|
2244
|
+
data.where = convertDatesInWhereClause(where);
|
|
1885
2245
|
}
|
|
1886
2246
|
|
|
1887
2247
|
if (columns) {
|
|
@@ -2079,6 +2439,87 @@ Examples:
|
|
|
2079
2439
|
break;
|
|
2080
2440
|
}
|
|
2081
2441
|
|
|
2442
|
+
case 'ref': {
|
|
2443
|
+
const refSearch = require('../src/ref-search');
|
|
2444
|
+
const topicIndex = args.indexOf('--topic');
|
|
2445
|
+
const listTopics = args.includes('--list-topics') || args.includes('-l');
|
|
2446
|
+
const listRepos = args.includes('--list-repos') || args.includes('-r');
|
|
2447
|
+
const exportGuidelines = args.includes('--export') || args.includes('-e');
|
|
2448
|
+
const jsonOutput = args.includes('--json');
|
|
2449
|
+
|
|
2450
|
+
if (exportGuidelines) {
|
|
2451
|
+
const result = await refSearch.exportGuidelines();
|
|
2452
|
+
if (jsonOutput) {
|
|
2453
|
+
console.log(JSON.stringify(result, null, 2));
|
|
2454
|
+
} else {
|
|
2455
|
+
refSearch.displayExportResult(result);
|
|
2456
|
+
}
|
|
2457
|
+
break;
|
|
2458
|
+
}
|
|
2459
|
+
|
|
2460
|
+
if (listRepos) {
|
|
2461
|
+
const result = await refSearch.listRepositories();
|
|
2462
|
+
if (jsonOutput) {
|
|
2463
|
+
console.log(JSON.stringify(result, null, 2));
|
|
2464
|
+
} else {
|
|
2465
|
+
refSearch.displayRepositories(result);
|
|
2466
|
+
}
|
|
2467
|
+
break;
|
|
2468
|
+
}
|
|
2469
|
+
|
|
2470
|
+
if (listTopics) {
|
|
2471
|
+
const result = await refSearch.listTopics();
|
|
2472
|
+
if (jsonOutput) {
|
|
2473
|
+
console.log(JSON.stringify(result, null, 2));
|
|
2474
|
+
} else {
|
|
2475
|
+
refSearch.displayTopics(result);
|
|
2476
|
+
}
|
|
2477
|
+
break;
|
|
2478
|
+
}
|
|
2479
|
+
|
|
2480
|
+
if (topicIndex !== -1 && topicIndex + 1 < args.length) {
|
|
2481
|
+
const topic = args[topicIndex + 1];
|
|
2482
|
+
const result = await refSearch.getTopic(topic);
|
|
2483
|
+
if (jsonOutput) {
|
|
2484
|
+
console.log(JSON.stringify(result, null, 2));
|
|
2485
|
+
} else {
|
|
2486
|
+
refSearch.displayTopic(result);
|
|
2487
|
+
}
|
|
2488
|
+
break;
|
|
2489
|
+
}
|
|
2490
|
+
|
|
2491
|
+
// Pattern search (default)
|
|
2492
|
+
const patternIndex = args.findIndex((arg, idx) => idx > 0 && !arg.startsWith('--'));
|
|
2493
|
+
if (patternIndex === -1) {
|
|
2494
|
+
console.error('Error: No pattern specified');
|
|
2495
|
+
console.error('');
|
|
2496
|
+
console.error('Usage:');
|
|
2497
|
+
console.error(' abapgit-agent ref <pattern> Search for pattern');
|
|
2498
|
+
console.error(' abapgit-agent ref --topic <name> View specific topic');
|
|
2499
|
+
console.error(' abapgit-agent ref --list-topics List available topics');
|
|
2500
|
+
console.error(' abapgit-agent ref --list-repos List reference repositories');
|
|
2501
|
+
console.error(' abapgit-agent ref --export Export local guidelines to reference folder');
|
|
2502
|
+
console.error('');
|
|
2503
|
+
console.error('Examples:');
|
|
2504
|
+
console.error(' abapgit-agent ref "CORRESPONDING"');
|
|
2505
|
+
console.error(' abapgit-agent ref --topic exceptions');
|
|
2506
|
+
console.error(' abapgit-agent ref --list-topics');
|
|
2507
|
+
console.error(' abapgit-agent ref --list-repos');
|
|
2508
|
+
console.error(' abapgit-agent ref --export');
|
|
2509
|
+
process.exit(1);
|
|
2510
|
+
}
|
|
2511
|
+
|
|
2512
|
+
const pattern = args[patternIndex];
|
|
2513
|
+
const result = await refSearch.searchPattern(pattern);
|
|
2514
|
+
|
|
2515
|
+
if (jsonOutput) {
|
|
2516
|
+
console.log(JSON.stringify(result, null, 2));
|
|
2517
|
+
} else {
|
|
2518
|
+
refSearch.displaySearchResults(result);
|
|
2519
|
+
}
|
|
2520
|
+
break;
|
|
2521
|
+
}
|
|
2522
|
+
|
|
2082
2523
|
case 'help':
|
|
2083
2524
|
case '--help':
|
|
2084
2525
|
case '-h':
|
|
@@ -2091,6 +2532,8 @@ Usage:
|
|
|
2091
2532
|
Commands:
|
|
2092
2533
|
init --folder <folder> --package <package>
|
|
2093
2534
|
Initialize local configuration for an existing git repository.
|
|
2535
|
+
init --update
|
|
2536
|
+
Update existing files (CLAUDE.md, copilot-instructions.md, guidelines) to latest version.
|
|
2094
2537
|
|
|
2095
2538
|
create
|
|
2096
2539
|
Create abapGit online repository in ABAP system.
|
|
@@ -2112,12 +2555,30 @@ Commands:
|
|
|
2112
2555
|
unit --files <file1>,<file2>,...
|
|
2113
2556
|
Run AUnit tests for ABAP test class files (.testclasses.abap)
|
|
2114
2557
|
|
|
2115
|
-
tree --package <package> [--depth <n>] [--include-
|
|
2558
|
+
tree --package <package> [--depth <n>] [--include-types] [--json]
|
|
2116
2559
|
Display package hierarchy tree from ABAP system
|
|
2117
2560
|
|
|
2561
|
+
list --package <package> [--type <types>] [--name <pattern>] [--limit <n>] [--offset <n>] [--json]
|
|
2562
|
+
List ABAP objects in a package with filtering and pagination
|
|
2563
|
+
|
|
2118
2564
|
view --objects <obj1>,<obj2>,... [--type <type>] [--json]
|
|
2119
2565
|
View ABAP object definitions from the ABAP system
|
|
2120
2566
|
|
|
2567
|
+
ref <pattern> [--json]
|
|
2568
|
+
Search ABAP reference repositories for patterns. Requires referenceFolder in .abapGitAgent.
|
|
2569
|
+
|
|
2570
|
+
ref --topic <topic> [--json]
|
|
2571
|
+
View specific topic from cheat sheets (exceptions, sql, unit-tests, etc.)
|
|
2572
|
+
|
|
2573
|
+
ref --list-topics
|
|
2574
|
+
List available topics for reference search
|
|
2575
|
+
|
|
2576
|
+
ref --list-repos
|
|
2577
|
+
List all reference repositories in the reference folder
|
|
2578
|
+
|
|
2579
|
+
ref --export
|
|
2580
|
+
Export custom guidelines (abap/guidelines/) to reference folder
|
|
2581
|
+
|
|
2121
2582
|
health
|
|
2122
2583
|
Check if ABAP REST API is healthy
|
|
2123
2584
|
|
|
@@ -2126,6 +2587,7 @@ Commands:
|
|
|
2126
2587
|
|
|
2127
2588
|
Examples:
|
|
2128
2589
|
abapgit-agent init --folder /src --package ZMY_PACKAGE # Initialize
|
|
2590
|
+
abapgit-agent init --update # Update files to latest
|
|
2129
2591
|
abapgit-agent create # Create repo
|
|
2130
2592
|
abapgit-agent import # Import objects to git
|
|
2131
2593
|
abapgit-agent import --message "Initial import" # Import with message
|
|
@@ -2135,14 +2597,27 @@ Examples:
|
|
|
2135
2597
|
abapgit-agent pull --transport DEVK900001 # With transport
|
|
2136
2598
|
abapgit-agent inspect --files zcl_my_class.clas.abap # Syntax check
|
|
2137
2599
|
abapgit-agent unit --files zcl_my_test.clas.testclasses.abap # Run tests
|
|
2138
|
-
abapgit-agent tree --package
|
|
2139
|
-
abapgit-agent tree --package
|
|
2140
|
-
abapgit-agent tree --package
|
|
2141
|
-
abapgit-agent tree --package
|
|
2600
|
+
abapgit-agent tree --package \$ZMY_PACKAGE # Show package tree
|
|
2601
|
+
abapgit-agent tree --package \$ZMY_PACKAGE --depth 2 # Shallow tree
|
|
2602
|
+
abapgit-agent tree --package \$ZMY_PACKAGE --include-types # With type counts
|
|
2603
|
+
abapgit-agent tree --package \$ZMY_PACKAGE --json # JSON output
|
|
2604
|
+
abapgit-agent list --package $ZMY_PACKAGE # List all objects
|
|
2605
|
+
abapgit-agent list --package $ZMY_PACKAGE --type CLAS,INTF # Filter by type
|
|
2606
|
+
abapgit-agent list --package $ZMY_PACKAGE --name ZCL_* # Filter by name
|
|
2607
|
+
abapgit-agent list --package $ZMY_PACKAGE --limit 50 # Limit results
|
|
2608
|
+
abapgit-agent list --package $ZMY_PACKAGE --json # JSON output
|
|
2142
2609
|
abapgit-agent view --objects ZCL_MY_CLASS # View class definition
|
|
2143
2610
|
abapgit-agent view --objects ZIF_MY_INTERFACE --type INTF # View interface
|
|
2144
2611
|
abapgit-agent view --objects ZMY_TABLE --type TABL # View table structure
|
|
2145
2612
|
abapgit-agent view --objects ZCL_CLASS1,ZCL_CLASS2 --json # Multiple objects
|
|
2613
|
+
abapgit-agent ref "CORRESPONDING" # Search all reference repos
|
|
2614
|
+
abapgit-agent ref "CX_SY_" # Search exceptions
|
|
2615
|
+
abapgit-agent ref --topic exceptions # View exception topic
|
|
2616
|
+
abapgit-agent ref --topic sql # View SQL topic
|
|
2617
|
+
abapgit-agent ref --topic unit-tests # View unit test topic
|
|
2618
|
+
abapgit-agent ref --list-topics # List all topics
|
|
2619
|
+
abapgit-agent ref --list-repos # List reference repositories
|
|
2620
|
+
abapgit-agent ref --export # Export custom guidelines
|
|
2146
2621
|
abapgit-agent health
|
|
2147
2622
|
abapgit-agent status
|
|
2148
2623
|
`);
|