abapgit-agent 1.4.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/abap/guidelines/00_index.md +35 -0
- package/abap/guidelines/01_sql.md +72 -0
- package/abap/guidelines/02_exceptions.md +108 -0
- package/abap/guidelines/03_testing.md +252 -0
- package/abap/guidelines/04_cds.md +120 -0
- package/abap/guidelines/05_classes.md +50 -0
- package/abap/guidelines/06_objects.md +103 -0
- package/abap/guidelines/07_json.md +22 -0
- package/abap/guidelines/08_abapgit.md +193 -0
- package/bin/abapgit-agent +597 -44
- package/bin/abgagt +24 -0
- package/package.json +11 -3
- package/src/abap-client.js +65 -2
- package/src/agent.js +58 -4
- package/src/config.js +9 -2
- package/src/ref-search.js +989 -0
- package/.abapGitAgent.example +0 -11
- package/.github/workflows/release.yml +0 -57
- package/API.md +0 -710
- package/CLAUDE.md +0 -1031
- 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 -898
- 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 -411
- 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 -62
- 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 -158
- package/docs/preview-command.md +0 -528
- package/docs/pull-command.md +0 -188
- 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.sh +0 -60
- package/scripts/test-integration.js +0 -139
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,95 @@ 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
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Get CLI version from package.json
|
|
50
|
+
*/
|
|
51
|
+
function getCliVersion() {
|
|
52
|
+
const packageJsonPath = pathModule.join(__dirname, '..', 'package.json');
|
|
53
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
54
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
55
|
+
return pkg.version || '1.0.0';
|
|
56
|
+
}
|
|
57
|
+
return '1.0.0';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Check version compatibility between CLI and ABAP API
|
|
62
|
+
*/
|
|
63
|
+
async function checkVersionCompatibility() {
|
|
64
|
+
const cliVersion = getCliVersion();
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
const config = loadConfig();
|
|
68
|
+
const https = require('https');
|
|
69
|
+
const url = new URL(`/sap/bc/z_abapgit_agent/health`, `https://${config.host}:${config.sapport}`);
|
|
70
|
+
|
|
71
|
+
return new Promise((resolve) => {
|
|
72
|
+
const options = {
|
|
73
|
+
hostname: url.hostname,
|
|
74
|
+
port: url.port,
|
|
75
|
+
path: url.pathname,
|
|
76
|
+
method: 'GET',
|
|
77
|
+
headers: {
|
|
78
|
+
'Authorization': `Basic ${Buffer.from(`${config.user}:${config.password}`).toString('base64')}`,
|
|
79
|
+
'sap-client': config.client,
|
|
80
|
+
'sap-language': config.language || 'EN',
|
|
81
|
+
'Content-Type': 'application/json'
|
|
82
|
+
},
|
|
83
|
+
agent: new https.Agent({ rejectUnauthorized: false })
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const req = https.request(options, (res) => {
|
|
87
|
+
let body = '';
|
|
88
|
+
res.on('data', chunk => body += chunk);
|
|
89
|
+
res.on('end', () => {
|
|
90
|
+
try {
|
|
91
|
+
const result = JSON.parse(body);
|
|
92
|
+
const apiVersion = result.version || '1.0.0';
|
|
93
|
+
|
|
94
|
+
if (cliVersion !== apiVersion) {
|
|
95
|
+
console.log(`\n⚠️ Version mismatch: CLI ${cliVersion}, ABAP API ${apiVersion}`);
|
|
96
|
+
console.log(' Some commands may not work correctly.');
|
|
97
|
+
console.log(' Update ABAP code: abapgit-agent pull\n');
|
|
98
|
+
}
|
|
99
|
+
resolve({ cliVersion, apiVersion, compatible: cliVersion === apiVersion });
|
|
100
|
+
} catch (e) {
|
|
101
|
+
resolve({ cliVersion, apiVersion: null, compatible: false, error: e.message });
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
req.on('error', (e) => {
|
|
107
|
+
resolve({ cliVersion, apiVersion: null, compatible: false, error: e.message });
|
|
108
|
+
});
|
|
109
|
+
req.end();
|
|
110
|
+
});
|
|
111
|
+
} catch (error) {
|
|
112
|
+
return { cliVersion, apiVersion: null, compatible: false, error: error.message };
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
26
116
|
/**
|
|
27
117
|
* Load configuration from .abapGitAgent in current working directory
|
|
28
118
|
*/
|
|
@@ -42,10 +132,19 @@ function loadConfig() {
|
|
|
42
132
|
password: process.env.ABAP_PASSWORD,
|
|
43
133
|
language: process.env.ABAP_LANGUAGE || 'EN',
|
|
44
134
|
gitUsername: process.env.GIT_USERNAME,
|
|
45
|
-
gitPassword: process.env.GIT_PASSWORD
|
|
135
|
+
gitPassword: process.env.GIT_PASSWORD,
|
|
136
|
+
transport: process.env.ABAP_TRANSPORT
|
|
46
137
|
};
|
|
47
138
|
}
|
|
48
139
|
|
|
140
|
+
/**
|
|
141
|
+
* Get transport request from config or environment
|
|
142
|
+
*/
|
|
143
|
+
function getTransport() {
|
|
144
|
+
const config = loadConfig();
|
|
145
|
+
return config.transport;
|
|
146
|
+
}
|
|
147
|
+
|
|
49
148
|
/**
|
|
50
149
|
* Check if ABAP integration is configured for this repo
|
|
51
150
|
*/
|
|
@@ -385,7 +484,7 @@ async function syntaxCheckSource(sourceFile, csrfToken, config) {
|
|
|
385
484
|
/**
|
|
386
485
|
* Inspect all files in one request
|
|
387
486
|
*/
|
|
388
|
-
async function inspectAllFiles(files, csrfToken, config) {
|
|
487
|
+
async function inspectAllFiles(files, csrfToken, config, variant = null) {
|
|
389
488
|
// Convert files to uppercase names (same as syntaxCheckSource does)
|
|
390
489
|
const fileNames = files.map(f => {
|
|
391
490
|
const baseName = pathModule.basename(f).toUpperCase();
|
|
@@ -398,6 +497,11 @@ async function inspectAllFiles(files, csrfToken, config) {
|
|
|
398
497
|
files: fileNames
|
|
399
498
|
};
|
|
400
499
|
|
|
500
|
+
// Add variant if specified
|
|
501
|
+
if (variant) {
|
|
502
|
+
data.variant = variant;
|
|
503
|
+
}
|
|
504
|
+
|
|
401
505
|
const result = await request('POST', '/sap/bc/z_abapgit_agent/inspect', data, { csrfToken: csrfToken });
|
|
402
506
|
|
|
403
507
|
// Handle both table result and old single result
|
|
@@ -624,11 +728,11 @@ async function runUnitTestForFile(sourceFile, csrfToken, config) {
|
|
|
624
728
|
/**
|
|
625
729
|
* Run tree command and return raw result
|
|
626
730
|
*/
|
|
627
|
-
async function runTreeCommand(packageName, depth,
|
|
731
|
+
async function runTreeCommand(packageName, depth, includeTypes, csrfToken, config) {
|
|
628
732
|
const data = {
|
|
629
733
|
package: packageName,
|
|
630
734
|
depth: depth,
|
|
631
|
-
include_objects:
|
|
735
|
+
include_objects: includeTypes
|
|
632
736
|
};
|
|
633
737
|
|
|
634
738
|
return await request('POST', '/sap/bc/z_abapgit_agent/tree', data, { csrfToken });
|
|
@@ -637,13 +741,13 @@ async function runTreeCommand(packageName, depth, includeObjects, csrfToken, con
|
|
|
637
741
|
/**
|
|
638
742
|
* Display tree output in human-readable format
|
|
639
743
|
*/
|
|
640
|
-
async function displayTreeOutput(packageName, depth,
|
|
744
|
+
async function displayTreeOutput(packageName, depth, includeTypes) {
|
|
641
745
|
const config = loadConfig();
|
|
642
746
|
const csrfToken = await fetchCsrfToken(config);
|
|
643
747
|
|
|
644
748
|
console.log(`\n Getting package tree for: ${packageName}`);
|
|
645
749
|
|
|
646
|
-
const result = await runTreeCommand(packageName, depth,
|
|
750
|
+
const result = await runTreeCommand(packageName, depth, includeTypes, csrfToken, config);
|
|
647
751
|
|
|
648
752
|
// Handle uppercase keys from ABAP
|
|
649
753
|
const success = result.SUCCESS || result.success;
|
|
@@ -683,7 +787,7 @@ async function displayTreeOutput(packageName, depth, includeObjects) {
|
|
|
683
787
|
console.log(` OBJECTS: ${totalObjects}`);
|
|
684
788
|
|
|
685
789
|
// Display object types if available
|
|
686
|
-
if (
|
|
790
|
+
if (includeTypes && objectTypes.length > 0) {
|
|
687
791
|
const typeStr = objectTypes.map(t => `${t.OBJECT || t.object}=${t.COUNT || t.count}`).join(' ');
|
|
688
792
|
console.log(` TYPES: ${typeStr}`);
|
|
689
793
|
}
|
|
@@ -986,12 +1090,86 @@ async function pull(gitUrl, branch = 'main', files = null, transportRequest = nu
|
|
|
986
1090
|
}
|
|
987
1091
|
}
|
|
988
1092
|
|
|
1093
|
+
/**
|
|
1094
|
+
* Copy a file if source exists (helper for init --update)
|
|
1095
|
+
* @param {string} srcPath - Source file path
|
|
1096
|
+
* @param {string} destPath - Destination file path
|
|
1097
|
+
* @param {string} label - Label for console output
|
|
1098
|
+
* @param {boolean} createParentDir - Whether to create parent directory
|
|
1099
|
+
* @returns {Promise<void>}
|
|
1100
|
+
*/
|
|
1101
|
+
async function copyFileIfExists(srcPath, destPath, label, createParentDir = false) {
|
|
1102
|
+
try {
|
|
1103
|
+
if (fs.existsSync(srcPath)) {
|
|
1104
|
+
if (createParentDir) {
|
|
1105
|
+
const parentDir = pathModule.dirname(destPath);
|
|
1106
|
+
if (!fs.existsSync(parentDir)) {
|
|
1107
|
+
fs.mkdirSync(parentDir, { recursive: true });
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
fs.copyFileSync(srcPath, destPath);
|
|
1111
|
+
console.log(`✅ Updated ${label}`);
|
|
1112
|
+
} else {
|
|
1113
|
+
console.log(`⚠️ ${label} not found in abapgit-agent`);
|
|
1114
|
+
}
|
|
1115
|
+
} catch (error) {
|
|
1116
|
+
console.error(`Error copying ${label}: ${error.message}`);
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
/**
|
|
1121
|
+
* Copy guidelines folder (helper for init --update)
|
|
1122
|
+
* @param {string} srcPath - Source folder path
|
|
1123
|
+
* @param {string} destPath - Destination folder path
|
|
1124
|
+
* @param {boolean} overwrite - Whether to overwrite existing files
|
|
1125
|
+
* @returns {Promise<void>}
|
|
1126
|
+
*/
|
|
1127
|
+
async function copyGuidelinesFolder(srcPath, destPath, overwrite = false) {
|
|
1128
|
+
try {
|
|
1129
|
+
if (fs.existsSync(srcPath)) {
|
|
1130
|
+
// Create destination directory if needed
|
|
1131
|
+
if (!fs.existsSync(destPath)) {
|
|
1132
|
+
fs.mkdirSync(destPath, { recursive: true });
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
const files = fs.readdirSync(srcPath);
|
|
1136
|
+
let copied = 0;
|
|
1137
|
+
|
|
1138
|
+
for (const file of files) {
|
|
1139
|
+
if (file.endsWith('.md')) {
|
|
1140
|
+
const srcFile = pathModule.join(srcPath, file);
|
|
1141
|
+
const destFile = pathModule.join(destPath, file);
|
|
1142
|
+
|
|
1143
|
+
// Skip if file exists and not overwriting
|
|
1144
|
+
if (fs.existsSync(destFile) && !overwrite) {
|
|
1145
|
+
continue;
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
fs.copyFileSync(srcFile, destFile);
|
|
1149
|
+
copied++;
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
if (copied > 0) {
|
|
1154
|
+
console.log(`✅ Updated guidelines/ (${copied} files)`);
|
|
1155
|
+
} else {
|
|
1156
|
+
console.log(`⚠️ No guideline files found`);
|
|
1157
|
+
}
|
|
1158
|
+
} else {
|
|
1159
|
+
console.log(`⚠️ guidelines folder not found in abapgit-agent`);
|
|
1160
|
+
}
|
|
1161
|
+
} catch (error) {
|
|
1162
|
+
console.error(`Error copying guidelines: ${error.message}`);
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
|
|
989
1166
|
/**
|
|
990
1167
|
* Run init command - Initialize local configuration
|
|
991
1168
|
*/
|
|
992
1169
|
async function runInit(args) {
|
|
993
1170
|
const folderArgIndex = args.indexOf('--folder');
|
|
994
1171
|
const packageArgIndex = args.indexOf('--package');
|
|
1172
|
+
const updateMode = args.includes('--update');
|
|
995
1173
|
|
|
996
1174
|
// Get parameters
|
|
997
1175
|
const folder = folderArgIndex !== -1 && folderArgIndex + 1 < args.length
|
|
@@ -1002,18 +1180,14 @@ async function runInit(args) {
|
|
|
1002
1180
|
? args[packageArgIndex + 1]
|
|
1003
1181
|
: null;
|
|
1004
1182
|
|
|
1005
|
-
// Validate package is required
|
|
1006
|
-
if (!packageName) {
|
|
1183
|
+
// Validate package is required for non-update mode
|
|
1184
|
+
if (!updateMode && !packageName) {
|
|
1007
1185
|
console.error('Error: --package is required');
|
|
1008
1186
|
console.error('Usage: abapgit-agent init --folder /src --package ZMY_PACKAGE');
|
|
1187
|
+
console.error(' abapgit-agent init --update # Update files to latest version');
|
|
1009
1188
|
process.exit(1);
|
|
1010
1189
|
}
|
|
1011
1190
|
|
|
1012
|
-
console.log(`\n🚀 Initializing abapGit Agent for local repository`);
|
|
1013
|
-
console.log(` Folder: ${folder}`);
|
|
1014
|
-
console.log(` Package: ${packageName}`);
|
|
1015
|
-
console.log('');
|
|
1016
|
-
|
|
1017
1191
|
// Check if current folder is git repo root
|
|
1018
1192
|
const gitDir = pathModule.join(process.cwd(), '.git');
|
|
1019
1193
|
if (!fs.existsSync(gitDir)) {
|
|
@@ -1022,6 +1196,53 @@ async function runInit(args) {
|
|
|
1022
1196
|
process.exit(1);
|
|
1023
1197
|
}
|
|
1024
1198
|
|
|
1199
|
+
// In update mode, just copy the files and return
|
|
1200
|
+
if (updateMode) {
|
|
1201
|
+
console.log(`\n🔄 Updating abapGit Agent files`);
|
|
1202
|
+
console.log('');
|
|
1203
|
+
|
|
1204
|
+
// Copy CLAUDE.md
|
|
1205
|
+
await copyFileIfExists(
|
|
1206
|
+
pathModule.join(__dirname, '..', 'abap', 'CLAUDE.md'),
|
|
1207
|
+
pathModule.join(process.cwd(), 'CLAUDE.md'),
|
|
1208
|
+
'CLAUDE.md'
|
|
1209
|
+
);
|
|
1210
|
+
|
|
1211
|
+
// Copy copilot-instructions.md
|
|
1212
|
+
await copyFileIfExists(
|
|
1213
|
+
pathModule.join(__dirname, '..', 'abap', '.github', 'copilot-instructions.md'),
|
|
1214
|
+
pathModule.join(process.cwd(), '.github', 'copilot-instructions.md'),
|
|
1215
|
+
'.github/copilot-instructions.md',
|
|
1216
|
+
true // create parent dir
|
|
1217
|
+
);
|
|
1218
|
+
|
|
1219
|
+
// Copy guidelines folder to project root
|
|
1220
|
+
await copyGuidelinesFolder(
|
|
1221
|
+
pathModule.join(__dirname, '..', 'abap', 'guidelines'),
|
|
1222
|
+
pathModule.join(process.cwd(), 'guidelines'),
|
|
1223
|
+
true // overwrite
|
|
1224
|
+
);
|
|
1225
|
+
|
|
1226
|
+
console.log(`
|
|
1227
|
+
📋 Update complete!
|
|
1228
|
+
Run 'abapgit-agent ref --list-topics' to see available topics.
|
|
1229
|
+
`);
|
|
1230
|
+
return;
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
// Validate package is required
|
|
1234
|
+
if (!packageName) {
|
|
1235
|
+
console.error('Error: --package is required');
|
|
1236
|
+
console.error('Usage: abapgit-agent init --folder /src --package ZMY_PACKAGE');
|
|
1237
|
+
console.error(' abapgit-agent init --update # Update files to latest version');
|
|
1238
|
+
process.exit(1);
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
console.log(`\n🚀 Initializing abapGit Agent for local repository`);
|
|
1242
|
+
console.log(` Folder: ${folder}`);
|
|
1243
|
+
console.log(` Package: ${packageName}`);
|
|
1244
|
+
console.log('');
|
|
1245
|
+
|
|
1025
1246
|
// Detect git remote URL
|
|
1026
1247
|
const gitUrl = getGitRemoteUrl();
|
|
1027
1248
|
if (!gitUrl) {
|
|
@@ -1106,7 +1327,7 @@ async function runInit(args) {
|
|
|
1106
1327
|
}
|
|
1107
1328
|
|
|
1108
1329
|
// Copy copilot-instructions.md for GitHub Copilot
|
|
1109
|
-
const copilotMdPath = pathModule.join(__dirname, '..', 'abap', 'copilot-instructions.md');
|
|
1330
|
+
const copilotMdPath = pathModule.join(__dirname, '..', 'abap', '.github', 'copilot-instructions.md');
|
|
1110
1331
|
const githubDir = pathModule.join(process.cwd(), '.github');
|
|
1111
1332
|
const localCopilotMdPath = pathModule.join(githubDir, 'copilot-instructions.md');
|
|
1112
1333
|
try {
|
|
@@ -1124,6 +1345,35 @@ async function runInit(args) {
|
|
|
1124
1345
|
console.error(`Error copying copilot-instructions.md: ${error.message}`);
|
|
1125
1346
|
}
|
|
1126
1347
|
|
|
1348
|
+
// Copy guidelines folder to project root
|
|
1349
|
+
const guidelinesSrcPath = pathModule.join(__dirname, '..', 'abap', 'guidelines');
|
|
1350
|
+
const guidelinesDestPath = pathModule.join(process.cwd(), 'guidelines');
|
|
1351
|
+
try {
|
|
1352
|
+
if (fs.existsSync(guidelinesSrcPath)) {
|
|
1353
|
+
if (!fs.existsSync(guidelinesDestPath)) {
|
|
1354
|
+
// Create guidelines directory
|
|
1355
|
+
fs.mkdirSync(guidelinesDestPath, { recursive: true });
|
|
1356
|
+
// Copy all files from guidelines folder
|
|
1357
|
+
const files = fs.readdirSync(guidelinesSrcPath);
|
|
1358
|
+
for (const file of files) {
|
|
1359
|
+
if (file.endsWith('.md')) {
|
|
1360
|
+
fs.copyFileSync(
|
|
1361
|
+
pathModule.join(guidelinesSrcPath, file),
|
|
1362
|
+
pathModule.join(guidelinesDestPath, file)
|
|
1363
|
+
);
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
console.log(`✅ Created guidelines/ (${files.filter(f => f.endsWith('.md')).length} files)`);
|
|
1367
|
+
} else {
|
|
1368
|
+
console.log(`⚠️ guidelines/ already exists, skipped`);
|
|
1369
|
+
}
|
|
1370
|
+
} else {
|
|
1371
|
+
console.log(`⚠️ guidelines folder not found in abap/ directory`);
|
|
1372
|
+
}
|
|
1373
|
+
} catch (error) {
|
|
1374
|
+
console.error(`Error copying guidelines: ${error.message}`);
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1127
1377
|
// Create folder
|
|
1128
1378
|
const folderPath = pathModule.join(process.cwd(), folder);
|
|
1129
1379
|
try {
|
|
@@ -1171,8 +1421,9 @@ async function main() {
|
|
|
1171
1421
|
const command = args[0];
|
|
1172
1422
|
|
|
1173
1423
|
// Check if ABAP integration is enabled for this repo
|
|
1174
|
-
// (skip for init, help commands)
|
|
1175
|
-
|
|
1424
|
+
// (skip for init, help, ref commands - these don't need ABAP connection)
|
|
1425
|
+
const noAbapRequired = ['init', 'help', '--help', '-h', 'ref'];
|
|
1426
|
+
if (command && !noAbapRequired.includes(command)) {
|
|
1176
1427
|
if (!isAbapIntegrationEnabled()) {
|
|
1177
1428
|
console.log(`
|
|
1178
1429
|
⚠️ ABAP Git Agent not configured for this repository.
|
|
@@ -1195,6 +1446,12 @@ To enable integration:
|
|
|
1195
1446
|
}
|
|
1196
1447
|
}
|
|
1197
1448
|
|
|
1449
|
+
// Version compatibility check for commands that interact with ABAP
|
|
1450
|
+
const abapCommands = ['create', 'import', 'pull', 'inspect', 'unit', 'tree', 'view', 'preview', 'list'];
|
|
1451
|
+
if (command && abapCommands.includes(command)) {
|
|
1452
|
+
await checkVersionCompatibility();
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1198
1455
|
try {
|
|
1199
1456
|
switch (command) {
|
|
1200
1457
|
case 'init':
|
|
@@ -1390,16 +1647,21 @@ Examples:
|
|
|
1390
1647
|
let gitUrl = urlArgIndex !== -1 ? args[urlArgIndex + 1] : null;
|
|
1391
1648
|
let branch = branchArgIndex !== -1 ? args[branchArgIndex + 1] : getGitBranch();
|
|
1392
1649
|
let files = null;
|
|
1650
|
+
|
|
1651
|
+
// Transport: CLI arg takes priority, then config/environment, then null
|
|
1393
1652
|
let transportRequest = null;
|
|
1653
|
+
if (transportArgIndex !== -1 && transportArgIndex + 1 < args.length) {
|
|
1654
|
+
// Explicit --transport argument
|
|
1655
|
+
transportRequest = args[transportArgIndex + 1];
|
|
1656
|
+
} else {
|
|
1657
|
+
// Fall back to config or environment variable
|
|
1658
|
+
transportRequest = getTransport();
|
|
1659
|
+
}
|
|
1394
1660
|
|
|
1395
1661
|
if (filesArgIndex !== -1 && filesArgIndex + 1 < args.length) {
|
|
1396
1662
|
files = args[filesArgIndex + 1].split(',').map(f => f.trim());
|
|
1397
1663
|
}
|
|
1398
1664
|
|
|
1399
|
-
if (transportArgIndex !== -1 && transportArgIndex + 1 < args.length) {
|
|
1400
|
-
transportRequest = args[transportArgIndex + 1];
|
|
1401
|
-
}
|
|
1402
|
-
|
|
1403
1665
|
if (!gitUrl) {
|
|
1404
1666
|
gitUrl = getGitRemoteUrl();
|
|
1405
1667
|
if (!gitUrl) {
|
|
@@ -1427,31 +1689,32 @@ Examples:
|
|
|
1427
1689
|
break;
|
|
1428
1690
|
|
|
1429
1691
|
case 'inspect': {
|
|
1430
|
-
// TODO: Implement full inspect feature with:
|
|
1431
|
-
// - Syntax check (currently implemented via /inspect)
|
|
1432
|
-
// - Code Inspector checks (SE51, SCI)
|
|
1433
|
-
// - ATC checks (SATC)
|
|
1434
|
-
// - Custom rule checks
|
|
1435
|
-
// Add --check-type parameter to specify which check to run
|
|
1436
|
-
|
|
1437
1692
|
const filesArgIndex = args.indexOf('--files');
|
|
1438
1693
|
if (filesArgIndex === -1 || filesArgIndex + 1 >= args.length) {
|
|
1439
1694
|
console.error('Error: --files parameter required');
|
|
1440
|
-
console.error('Usage: abapgit-agent inspect --files <file1>,<file2>,...');
|
|
1695
|
+
console.error('Usage: abapgit-agent inspect --files <file1>,<file2>,... [--variant <check-variant>]');
|
|
1441
1696
|
console.error('Example: abapgit-agent inspect --files zcl_my_class.clas.abap');
|
|
1697
|
+
console.error('Example: abapgit-agent inspect --files zcl_my_class.clas.abap --variant ALL_CHECKS');
|
|
1442
1698
|
process.exit(1);
|
|
1443
1699
|
}
|
|
1444
1700
|
|
|
1445
1701
|
const filesSyntaxCheck = args[filesArgIndex + 1].split(',').map(f => f.trim());
|
|
1446
1702
|
|
|
1703
|
+
// Parse optional --variant parameter
|
|
1704
|
+
const variantArgIndex = args.indexOf('--variant');
|
|
1705
|
+
const variant = variantArgIndex !== -1 ? args[variantArgIndex + 1] : null;
|
|
1706
|
+
|
|
1447
1707
|
console.log(`\n Inspect for ${filesSyntaxCheck.length} file(s)`);
|
|
1708
|
+
if (variant) {
|
|
1709
|
+
console.log(` Using variant: ${variant}`);
|
|
1710
|
+
}
|
|
1448
1711
|
console.log('');
|
|
1449
1712
|
|
|
1450
1713
|
const config = loadConfig();
|
|
1451
1714
|
const csrfToken = await fetchCsrfToken(config);
|
|
1452
1715
|
|
|
1453
1716
|
// Send all files in one request
|
|
1454
|
-
const results = await inspectAllFiles(filesSyntaxCheck, csrfToken, config);
|
|
1717
|
+
const results = await inspectAllFiles(filesSyntaxCheck, csrfToken, config, variant);
|
|
1455
1718
|
|
|
1456
1719
|
// Process results
|
|
1457
1720
|
for (const result of results) {
|
|
@@ -1485,15 +1748,37 @@ Examples:
|
|
|
1485
1748
|
|
|
1486
1749
|
case 'tree': {
|
|
1487
1750
|
const packageArgIndex = args.indexOf('--package');
|
|
1488
|
-
if (packageArgIndex === -1
|
|
1751
|
+
if (packageArgIndex === -1) {
|
|
1489
1752
|
console.error('Error: --package parameter required');
|
|
1490
|
-
console.error('Usage: abapgit-agent tree --package <package> [--depth <n>] [--include-
|
|
1491
|
-
console.error('Example: abapgit-agent tree --package
|
|
1753
|
+
console.error('Usage: abapgit-agent tree --package <package> [--depth <n>] [--include-types] [--json]');
|
|
1754
|
+
console.error('Example: abapgit-agent tree --package ZMY_PACKAGE');
|
|
1755
|
+
process.exit(1);
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
// Check if package value is missing (happens when shell variable expands to empty)
|
|
1759
|
+
if (packageArgIndex + 1 >= args.length) {
|
|
1760
|
+
console.error('Error: --package parameter value is missing');
|
|
1761
|
+
console.error('');
|
|
1762
|
+
console.error('Tip: If you are using a shell variable, make sure to quote it:');
|
|
1763
|
+
console.error(' abapgit-agent tree --package "$ZMY_PACKAGE"');
|
|
1764
|
+
console.error(' or escape the $ character:');
|
|
1765
|
+
console.error(' abapgit-agent tree --package \\$ZMY_PACKAGE');
|
|
1766
|
+
console.error('');
|
|
1767
|
+
console.error('Usage: abapgit-agent tree --package <package> [--depth <n>] [--include-types] [--json]');
|
|
1768
|
+
console.error('Example: abapgit-agent tree --package ZMY_PACKAGE');
|
|
1492
1769
|
process.exit(1);
|
|
1493
1770
|
}
|
|
1494
1771
|
|
|
1495
1772
|
const packageName = args[packageArgIndex + 1];
|
|
1496
1773
|
|
|
1774
|
+
// Check for empty/whitespace-only package name
|
|
1775
|
+
if (!packageName || packageName.trim() === '') {
|
|
1776
|
+
console.error('Error: --package parameter cannot be empty');
|
|
1777
|
+
console.error('Usage: abapgit-agent tree --package <package> [--depth <n>] [--include-types] [--json]');
|
|
1778
|
+
console.error('Example: abapgit-agent tree --package ZMY_PACKAGE');
|
|
1779
|
+
process.exit(1);
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1497
1782
|
// Optional depth parameter
|
|
1498
1783
|
const depthArgIndex = args.indexOf('--depth');
|
|
1499
1784
|
let depth = 3;
|
|
@@ -1505,8 +1790,8 @@ Examples:
|
|
|
1505
1790
|
}
|
|
1506
1791
|
}
|
|
1507
1792
|
|
|
1508
|
-
// Optional include-objects
|
|
1509
|
-
const
|
|
1793
|
+
// Optional include-types parameter (--include-objects is deprecated alias)
|
|
1794
|
+
const includeTypes = args.includes('--include-types') || args.includes('--include-objects');
|
|
1510
1795
|
|
|
1511
1796
|
// Optional json parameter
|
|
1512
1797
|
const jsonOutput = args.includes('--json');
|
|
@@ -1514,10 +1799,141 @@ Examples:
|
|
|
1514
1799
|
if (jsonOutput) {
|
|
1515
1800
|
const config = loadConfig();
|
|
1516
1801
|
const csrfToken = await fetchCsrfToken(config);
|
|
1517
|
-
const result = await runTreeCommand(packageName, depth,
|
|
1802
|
+
const result = await runTreeCommand(packageName, depth, includeTypes, csrfToken, config);
|
|
1518
1803
|
console.log(JSON.stringify(result, null, 2));
|
|
1519
1804
|
} else {
|
|
1520
|
-
await displayTreeOutput(packageName, depth,
|
|
1805
|
+
await displayTreeOutput(packageName, depth, includeTypes);
|
|
1806
|
+
}
|
|
1807
|
+
break;
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1810
|
+
case 'list': {
|
|
1811
|
+
const packageArgIndex = args.indexOf('--package');
|
|
1812
|
+
if (packageArgIndex === -1) {
|
|
1813
|
+
console.error('Error: --package parameter required');
|
|
1814
|
+
console.error('Usage: abapgit-agent list --package <package> [--type <types>] [--name <pattern>] [--limit <n>] [--offset <n>] [--json]');
|
|
1815
|
+
console.error('Example: abapgit-agent list --package $ZMY_PACKAGE');
|
|
1816
|
+
console.error('Example: abapgit-agent list --package $ZMY_PACKAGE --type CLAS,INTF');
|
|
1817
|
+
process.exit(1);
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
// Check if package value is missing
|
|
1821
|
+
if (packageArgIndex + 1 >= args.length) {
|
|
1822
|
+
console.error('Error: --package parameter value is missing');
|
|
1823
|
+
process.exit(1);
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
const packageName = args[packageArgIndex + 1];
|
|
1827
|
+
|
|
1828
|
+
// Validate package name
|
|
1829
|
+
if (!packageName || packageName.trim() === '') {
|
|
1830
|
+
console.error('Error: --package parameter cannot be empty');
|
|
1831
|
+
process.exit(1);
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
// Optional type parameter
|
|
1835
|
+
const typeArgIndex = args.indexOf('--type');
|
|
1836
|
+
const type = typeArgIndex !== -1 && typeArgIndex + 1 < args.length ? args[typeArgIndex + 1] : null;
|
|
1837
|
+
|
|
1838
|
+
// Optional name pattern
|
|
1839
|
+
const nameArgIndex = args.indexOf('--name');
|
|
1840
|
+
const name = nameArgIndex !== -1 && nameArgIndex + 1 < args.length ? args[nameArgIndex + 1] : null;
|
|
1841
|
+
|
|
1842
|
+
// Optional limit
|
|
1843
|
+
const limitArgIndex = args.indexOf('--limit');
|
|
1844
|
+
let limit = 100;
|
|
1845
|
+
if (limitArgIndex !== -1 && limitArgIndex + 1 < args.length) {
|
|
1846
|
+
limit = parseInt(args[limitArgIndex + 1], 10);
|
|
1847
|
+
if (isNaN(limit) || limit < 1) {
|
|
1848
|
+
console.error('Error: --limit must be a positive number');
|
|
1849
|
+
process.exit(1);
|
|
1850
|
+
}
|
|
1851
|
+
if (limit > 1000) {
|
|
1852
|
+
console.error('Error: --limit value too high (max: 1000)');
|
|
1853
|
+
process.exit(1);
|
|
1854
|
+
}
|
|
1855
|
+
}
|
|
1856
|
+
|
|
1857
|
+
// Optional offset
|
|
1858
|
+
const offsetArgIndex = args.indexOf('--offset');
|
|
1859
|
+
let offset = 0;
|
|
1860
|
+
if (offsetArgIndex !== -1 && offsetArgIndex + 1 < args.length) {
|
|
1861
|
+
offset = parseInt(args[offsetArgIndex + 1], 10);
|
|
1862
|
+
if (isNaN(offset) || offset < 0) {
|
|
1863
|
+
console.error('Error: --offset must be a non-negative number');
|
|
1864
|
+
process.exit(1);
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
|
|
1868
|
+
// Optional json parameter
|
|
1869
|
+
const jsonOutput = args.includes('--json');
|
|
1870
|
+
|
|
1871
|
+
const config = loadConfig();
|
|
1872
|
+
const csrfToken = await fetchCsrfToken(config);
|
|
1873
|
+
|
|
1874
|
+
const data = {
|
|
1875
|
+
package: packageName,
|
|
1876
|
+
limit: limit,
|
|
1877
|
+
offset: offset
|
|
1878
|
+
};
|
|
1879
|
+
|
|
1880
|
+
if (type) {
|
|
1881
|
+
data.type = type;
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1884
|
+
if (name) {
|
|
1885
|
+
data.name = name;
|
|
1886
|
+
}
|
|
1887
|
+
|
|
1888
|
+
const result = await request('POST', '/sap/bc/z_abapgit_agent/list', data, { csrfToken });
|
|
1889
|
+
|
|
1890
|
+
// Handle uppercase keys from ABAP
|
|
1891
|
+
const success = result.SUCCESS || result.success;
|
|
1892
|
+
const error = result.ERROR || result.error;
|
|
1893
|
+
const objects = result.OBJECTS || result.objects || [];
|
|
1894
|
+
const byType = result.BY_TYPE || result.by_type || [];
|
|
1895
|
+
const total = result.TOTAL || result.total || 0;
|
|
1896
|
+
|
|
1897
|
+
if (!success || error) {
|
|
1898
|
+
console.error(`\n Error: ${error || 'Failed to list objects'}`);
|
|
1899
|
+
process.exit(1);
|
|
1900
|
+
}
|
|
1901
|
+
|
|
1902
|
+
if (jsonOutput) {
|
|
1903
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1904
|
+
} else {
|
|
1905
|
+
// Display human-readable output
|
|
1906
|
+
let title = `Objects in ${packageName}`;
|
|
1907
|
+
if (type) {
|
|
1908
|
+
title += ` (${type} only`;
|
|
1909
|
+
if (total !== objects.length) {
|
|
1910
|
+
title += `, Total: ${total}`;
|
|
1911
|
+
}
|
|
1912
|
+
title += ')';
|
|
1913
|
+
} else if (total !== objects.length) {
|
|
1914
|
+
title += ` (Total: ${total})`;
|
|
1915
|
+
}
|
|
1916
|
+
console.log(`\n${title}\n`);
|
|
1917
|
+
|
|
1918
|
+
// Group objects by type
|
|
1919
|
+
const objectsByType = {};
|
|
1920
|
+
for (const obj of objects) {
|
|
1921
|
+
const objType = (obj.TYPE || obj.type || '???').toUpperCase();
|
|
1922
|
+
if (!objectsByType[objType]) {
|
|
1923
|
+
objectsByType[objType] = [];
|
|
1924
|
+
}
|
|
1925
|
+
objectsByType[objType].push(obj.NAME || obj.name);
|
|
1926
|
+
}
|
|
1927
|
+
|
|
1928
|
+
// Display grouped objects
|
|
1929
|
+
for (const objType of Object.keys(objectsByType).sort()) {
|
|
1930
|
+
const objNames = objectsByType[objType];
|
|
1931
|
+
console.log(` ${objType} (${objNames.length})`);
|
|
1932
|
+
for (const objName of objNames) {
|
|
1933
|
+
console.log(` ${objName}`);
|
|
1934
|
+
}
|
|
1935
|
+
console.log('');
|
|
1936
|
+
}
|
|
1521
1937
|
}
|
|
1522
1938
|
break;
|
|
1523
1939
|
}
|
|
@@ -1765,7 +2181,7 @@ Examples:
|
|
|
1765
2181
|
}
|
|
1766
2182
|
|
|
1767
2183
|
if (where) {
|
|
1768
|
-
data.where = where;
|
|
2184
|
+
data.where = convertDatesInWhereClause(where);
|
|
1769
2185
|
}
|
|
1770
2186
|
|
|
1771
2187
|
if (columns) {
|
|
@@ -1963,6 +2379,109 @@ Examples:
|
|
|
1963
2379
|
break;
|
|
1964
2380
|
}
|
|
1965
2381
|
|
|
2382
|
+
case 'ref': {
|
|
2383
|
+
const refSearch = require('../src/ref-search');
|
|
2384
|
+
const topicIndex = args.indexOf('--topic');
|
|
2385
|
+
const listTopics = args.includes('--list-topics') || args.includes('-l');
|
|
2386
|
+
const listRepos = args.includes('--list-repos') || args.includes('-r');
|
|
2387
|
+
const exportGuidelines = args.includes('--export') || args.includes('-e');
|
|
2388
|
+
const jsonOutput = args.includes('--json');
|
|
2389
|
+
|
|
2390
|
+
if (exportGuidelines) {
|
|
2391
|
+
const result = await refSearch.exportGuidelines();
|
|
2392
|
+
if (jsonOutput) {
|
|
2393
|
+
console.log(JSON.stringify(result, null, 2));
|
|
2394
|
+
} else {
|
|
2395
|
+
refSearch.displayExportResult(result);
|
|
2396
|
+
}
|
|
2397
|
+
break;
|
|
2398
|
+
}
|
|
2399
|
+
|
|
2400
|
+
if (listRepos) {
|
|
2401
|
+
const result = await refSearch.listRepositories();
|
|
2402
|
+
if (jsonOutput) {
|
|
2403
|
+
console.log(JSON.stringify(result, null, 2));
|
|
2404
|
+
} else {
|
|
2405
|
+
refSearch.displayRepositories(result);
|
|
2406
|
+
}
|
|
2407
|
+
break;
|
|
2408
|
+
}
|
|
2409
|
+
|
|
2410
|
+
if (listTopics) {
|
|
2411
|
+
const result = await refSearch.listTopics();
|
|
2412
|
+
if (jsonOutput) {
|
|
2413
|
+
console.log(JSON.stringify(result, null, 2));
|
|
2414
|
+
} else {
|
|
2415
|
+
refSearch.displayTopics(result);
|
|
2416
|
+
}
|
|
2417
|
+
break;
|
|
2418
|
+
}
|
|
2419
|
+
|
|
2420
|
+
if (topicIndex !== -1 && topicIndex + 1 < args.length) {
|
|
2421
|
+
const topic = args[topicIndex + 1];
|
|
2422
|
+
const result = await refSearch.getTopic(topic);
|
|
2423
|
+
if (jsonOutput) {
|
|
2424
|
+
console.log(JSON.stringify(result, null, 2));
|
|
2425
|
+
} else {
|
|
2426
|
+
refSearch.displayTopic(result);
|
|
2427
|
+
}
|
|
2428
|
+
break;
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2431
|
+
// Pattern search (default)
|
|
2432
|
+
const patternIndex = args.findIndex((arg, idx) => idx > 0 && !arg.startsWith('--'));
|
|
2433
|
+
if (patternIndex === -1) {
|
|
2434
|
+
console.error('Error: No pattern specified');
|
|
2435
|
+
console.error('');
|
|
2436
|
+
console.error('Usage:');
|
|
2437
|
+
console.error(' abapgit-agent ref <pattern> Search for pattern');
|
|
2438
|
+
console.error(' abapgit-agent ref --topic <name> View specific topic');
|
|
2439
|
+
console.error(' abapgit-agent ref --list-topics List available topics');
|
|
2440
|
+
console.error(' abapgit-agent ref --list-repos List reference repositories');
|
|
2441
|
+
console.error(' abapgit-agent ref --export Export local guidelines to reference folder');
|
|
2442
|
+
console.error('');
|
|
2443
|
+
console.error('Examples:');
|
|
2444
|
+
console.error(' abapgit-agent ref "CORRESPONDING"');
|
|
2445
|
+
console.error(' abapgit-agent ref --topic exceptions');
|
|
2446
|
+
console.error(' abapgit-agent ref --list-topics');
|
|
2447
|
+
console.error(' abapgit-agent ref --list-repos');
|
|
2448
|
+
console.error(' abapgit-agent ref --export');
|
|
2449
|
+
process.exit(1);
|
|
2450
|
+
}
|
|
2451
|
+
|
|
2452
|
+
const pattern = args[patternIndex];
|
|
2453
|
+
const result = await refSearch.searchPattern(pattern);
|
|
2454
|
+
|
|
2455
|
+
// Also search guidelines if available
|
|
2456
|
+
const guidelinesResult = await refSearch.searchGuidelines(pattern);
|
|
2457
|
+
if (guidelinesResult && guidelinesResult.guidelinesFound && guidelinesResult.matches.length > 0) {
|
|
2458
|
+
result.guidelines = guidelinesResult;
|
|
2459
|
+
}
|
|
2460
|
+
|
|
2461
|
+
if (jsonOutput) {
|
|
2462
|
+
console.log(JSON.stringify(result, null, 2));
|
|
2463
|
+
} else {
|
|
2464
|
+
refSearch.displaySearchResults(result);
|
|
2465
|
+
// Display guidelines results if found
|
|
2466
|
+
if (guidelinesResult && guidelinesResult.guidelinesFound && guidelinesResult.matches.length > 0) {
|
|
2467
|
+
console.log('\n 📋 Custom Guidelines:');
|
|
2468
|
+
for (const match of guidelinesResult.matches.slice(0, 5)) {
|
|
2469
|
+
console.log(` 📄 ${match.file} (line ${match.line}):`);
|
|
2470
|
+
const lines = match.context.split('\n');
|
|
2471
|
+
lines.forEach((line, idx) => {
|
|
2472
|
+
const prefix = idx === 1 ? ' → ' : ' ';
|
|
2473
|
+
const trimmed = line.slice(0, 80);
|
|
2474
|
+
console.log(`${prefix}${trimmed}`);
|
|
2475
|
+
});
|
|
2476
|
+
}
|
|
2477
|
+
if (guidelinesResult.matches.length > 5) {
|
|
2478
|
+
console.log(` ... and ${guidelinesResult.matches.length - 5} more matches`);
|
|
2479
|
+
}
|
|
2480
|
+
}
|
|
2481
|
+
}
|
|
2482
|
+
break;
|
|
2483
|
+
}
|
|
2484
|
+
|
|
1966
2485
|
case 'help':
|
|
1967
2486
|
case '--help':
|
|
1968
2487
|
case '-h':
|
|
@@ -1975,6 +2494,8 @@ Usage:
|
|
|
1975
2494
|
Commands:
|
|
1976
2495
|
init --folder <folder> --package <package>
|
|
1977
2496
|
Initialize local configuration for an existing git repository.
|
|
2497
|
+
init --update
|
|
2498
|
+
Update existing files (CLAUDE.md, copilot-instructions.md, guidelines) to latest version.
|
|
1978
2499
|
|
|
1979
2500
|
create
|
|
1980
2501
|
Create abapGit online repository in ABAP system.
|
|
@@ -1996,12 +2517,30 @@ Commands:
|
|
|
1996
2517
|
unit --files <file1>,<file2>,...
|
|
1997
2518
|
Run AUnit tests for ABAP test class files (.testclasses.abap)
|
|
1998
2519
|
|
|
1999
|
-
tree --package <package> [--depth <n>] [--include-
|
|
2520
|
+
tree --package <package> [--depth <n>] [--include-types] [--json]
|
|
2000
2521
|
Display package hierarchy tree from ABAP system
|
|
2001
2522
|
|
|
2523
|
+
list --package <package> [--type <types>] [--name <pattern>] [--limit <n>] [--offset <n>] [--json]
|
|
2524
|
+
List ABAP objects in a package with filtering and pagination
|
|
2525
|
+
|
|
2002
2526
|
view --objects <obj1>,<obj2>,... [--type <type>] [--json]
|
|
2003
2527
|
View ABAP object definitions from the ABAP system
|
|
2004
2528
|
|
|
2529
|
+
ref <pattern> [--json]
|
|
2530
|
+
Search ABAP reference repositories for patterns. Requires referenceFolder in .abapGitAgent.
|
|
2531
|
+
|
|
2532
|
+
ref --topic <topic> [--json]
|
|
2533
|
+
View specific topic from cheat sheets (exceptions, sql, unit-tests, etc.)
|
|
2534
|
+
|
|
2535
|
+
ref --list-topics
|
|
2536
|
+
List available topics for reference search
|
|
2537
|
+
|
|
2538
|
+
ref --list-repos
|
|
2539
|
+
List all reference repositories in the reference folder
|
|
2540
|
+
|
|
2541
|
+
ref --export
|
|
2542
|
+
Export custom guidelines (abap/guidelines/) to reference folder
|
|
2543
|
+
|
|
2005
2544
|
health
|
|
2006
2545
|
Check if ABAP REST API is healthy
|
|
2007
2546
|
|
|
@@ -2010,6 +2549,7 @@ Commands:
|
|
|
2010
2549
|
|
|
2011
2550
|
Examples:
|
|
2012
2551
|
abapgit-agent init --folder /src --package ZMY_PACKAGE # Initialize
|
|
2552
|
+
abapgit-agent init --update # Update files to latest
|
|
2013
2553
|
abapgit-agent create # Create repo
|
|
2014
2554
|
abapgit-agent import # Import objects to git
|
|
2015
2555
|
abapgit-agent import --message "Initial import" # Import with message
|
|
@@ -2019,14 +2559,27 @@ Examples:
|
|
|
2019
2559
|
abapgit-agent pull --transport DEVK900001 # With transport
|
|
2020
2560
|
abapgit-agent inspect --files zcl_my_class.clas.abap # Syntax check
|
|
2021
2561
|
abapgit-agent unit --files zcl_my_test.clas.testclasses.abap # Run tests
|
|
2022
|
-
abapgit-agent tree --package
|
|
2023
|
-
abapgit-agent tree --package
|
|
2024
|
-
abapgit-agent tree --package
|
|
2025
|
-
abapgit-agent tree --package
|
|
2562
|
+
abapgit-agent tree --package \$ZMY_PACKAGE # Show package tree
|
|
2563
|
+
abapgit-agent tree --package \$ZMY_PACKAGE --depth 2 # Shallow tree
|
|
2564
|
+
abapgit-agent tree --package \$ZMY_PACKAGE --include-types # With type counts
|
|
2565
|
+
abapgit-agent tree --package \$ZMY_PACKAGE --json # JSON output
|
|
2566
|
+
abapgit-agent list --package $ZMY_PACKAGE # List all objects
|
|
2567
|
+
abapgit-agent list --package $ZMY_PACKAGE --type CLAS,INTF # Filter by type
|
|
2568
|
+
abapgit-agent list --package $ZMY_PACKAGE --name ZCL_* # Filter by name
|
|
2569
|
+
abapgit-agent list --package $ZMY_PACKAGE --limit 50 # Limit results
|
|
2570
|
+
abapgit-agent list --package $ZMY_PACKAGE --json # JSON output
|
|
2026
2571
|
abapgit-agent view --objects ZCL_MY_CLASS # View class definition
|
|
2027
2572
|
abapgit-agent view --objects ZIF_MY_INTERFACE --type INTF # View interface
|
|
2028
2573
|
abapgit-agent view --objects ZMY_TABLE --type TABL # View table structure
|
|
2029
2574
|
abapgit-agent view --objects ZCL_CLASS1,ZCL_CLASS2 --json # Multiple objects
|
|
2575
|
+
abapgit-agent ref "CORRESPONDING" # Search all reference repos
|
|
2576
|
+
abapgit-agent ref "CX_SY_" # Search exceptions
|
|
2577
|
+
abapgit-agent ref --topic exceptions # View exception topic
|
|
2578
|
+
abapgit-agent ref --topic sql # View SQL topic
|
|
2579
|
+
abapgit-agent ref --topic unit-tests # View unit test topic
|
|
2580
|
+
abapgit-agent ref --list-topics # List all topics
|
|
2581
|
+
abapgit-agent ref --list-repos # List reference repositories
|
|
2582
|
+
abapgit-agent ref --export # Export custom guidelines
|
|
2030
2583
|
abapgit-agent health
|
|
2031
2584
|
abapgit-agent status
|
|
2032
2585
|
`);
|