abapgit-agent 1.5.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 +1 -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 +467 -30
- 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/ref-search.js +989 -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
|
*/
|
|
@@ -706,11 +728,11 @@ async function runUnitTestForFile(sourceFile, csrfToken, config) {
|
|
|
706
728
|
/**
|
|
707
729
|
* Run tree command and return raw result
|
|
708
730
|
*/
|
|
709
|
-
async function runTreeCommand(packageName, depth,
|
|
731
|
+
async function runTreeCommand(packageName, depth, includeTypes, csrfToken, config) {
|
|
710
732
|
const data = {
|
|
711
733
|
package: packageName,
|
|
712
734
|
depth: depth,
|
|
713
|
-
include_objects:
|
|
735
|
+
include_objects: includeTypes
|
|
714
736
|
};
|
|
715
737
|
|
|
716
738
|
return await request('POST', '/sap/bc/z_abapgit_agent/tree', data, { csrfToken });
|
|
@@ -719,13 +741,13 @@ async function runTreeCommand(packageName, depth, includeObjects, csrfToken, con
|
|
|
719
741
|
/**
|
|
720
742
|
* Display tree output in human-readable format
|
|
721
743
|
*/
|
|
722
|
-
async function displayTreeOutput(packageName, depth,
|
|
744
|
+
async function displayTreeOutput(packageName, depth, includeTypes) {
|
|
723
745
|
const config = loadConfig();
|
|
724
746
|
const csrfToken = await fetchCsrfToken(config);
|
|
725
747
|
|
|
726
748
|
console.log(`\n Getting package tree for: ${packageName}`);
|
|
727
749
|
|
|
728
|
-
const result = await runTreeCommand(packageName, depth,
|
|
750
|
+
const result = await runTreeCommand(packageName, depth, includeTypes, csrfToken, config);
|
|
729
751
|
|
|
730
752
|
// Handle uppercase keys from ABAP
|
|
731
753
|
const success = result.SUCCESS || result.success;
|
|
@@ -765,7 +787,7 @@ async function displayTreeOutput(packageName, depth, includeObjects) {
|
|
|
765
787
|
console.log(` OBJECTS: ${totalObjects}`);
|
|
766
788
|
|
|
767
789
|
// Display object types if available
|
|
768
|
-
if (
|
|
790
|
+
if (includeTypes && objectTypes.length > 0) {
|
|
769
791
|
const typeStr = objectTypes.map(t => `${t.OBJECT || t.object}=${t.COUNT || t.count}`).join(' ');
|
|
770
792
|
console.log(` TYPES: ${typeStr}`);
|
|
771
793
|
}
|
|
@@ -1068,12 +1090,86 @@ async function pull(gitUrl, branch = 'main', files = null, transportRequest = nu
|
|
|
1068
1090
|
}
|
|
1069
1091
|
}
|
|
1070
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
|
+
|
|
1071
1166
|
/**
|
|
1072
1167
|
* Run init command - Initialize local configuration
|
|
1073
1168
|
*/
|
|
1074
1169
|
async function runInit(args) {
|
|
1075
1170
|
const folderArgIndex = args.indexOf('--folder');
|
|
1076
1171
|
const packageArgIndex = args.indexOf('--package');
|
|
1172
|
+
const updateMode = args.includes('--update');
|
|
1077
1173
|
|
|
1078
1174
|
// Get parameters
|
|
1079
1175
|
const folder = folderArgIndex !== -1 && folderArgIndex + 1 < args.length
|
|
@@ -1084,18 +1180,14 @@ async function runInit(args) {
|
|
|
1084
1180
|
? args[packageArgIndex + 1]
|
|
1085
1181
|
: null;
|
|
1086
1182
|
|
|
1087
|
-
// Validate package is required
|
|
1088
|
-
if (!packageName) {
|
|
1183
|
+
// Validate package is required for non-update mode
|
|
1184
|
+
if (!updateMode && !packageName) {
|
|
1089
1185
|
console.error('Error: --package is required');
|
|
1090
1186
|
console.error('Usage: abapgit-agent init --folder /src --package ZMY_PACKAGE');
|
|
1187
|
+
console.error(' abapgit-agent init --update # Update files to latest version');
|
|
1091
1188
|
process.exit(1);
|
|
1092
1189
|
}
|
|
1093
1190
|
|
|
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
1191
|
// Check if current folder is git repo root
|
|
1100
1192
|
const gitDir = pathModule.join(process.cwd(), '.git');
|
|
1101
1193
|
if (!fs.existsSync(gitDir)) {
|
|
@@ -1104,6 +1196,53 @@ async function runInit(args) {
|
|
|
1104
1196
|
process.exit(1);
|
|
1105
1197
|
}
|
|
1106
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
|
+
|
|
1107
1246
|
// Detect git remote URL
|
|
1108
1247
|
const gitUrl = getGitRemoteUrl();
|
|
1109
1248
|
if (!gitUrl) {
|
|
@@ -1188,7 +1327,7 @@ async function runInit(args) {
|
|
|
1188
1327
|
}
|
|
1189
1328
|
|
|
1190
1329
|
// Copy copilot-instructions.md for GitHub Copilot
|
|
1191
|
-
const copilotMdPath = pathModule.join(__dirname, '..', 'abap', 'copilot-instructions.md');
|
|
1330
|
+
const copilotMdPath = pathModule.join(__dirname, '..', 'abap', '.github', 'copilot-instructions.md');
|
|
1192
1331
|
const githubDir = pathModule.join(process.cwd(), '.github');
|
|
1193
1332
|
const localCopilotMdPath = pathModule.join(githubDir, 'copilot-instructions.md');
|
|
1194
1333
|
try {
|
|
@@ -1206,6 +1345,35 @@ async function runInit(args) {
|
|
|
1206
1345
|
console.error(`Error copying copilot-instructions.md: ${error.message}`);
|
|
1207
1346
|
}
|
|
1208
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
|
+
|
|
1209
1377
|
// Create folder
|
|
1210
1378
|
const folderPath = pathModule.join(process.cwd(), folder);
|
|
1211
1379
|
try {
|
|
@@ -1253,8 +1421,9 @@ async function main() {
|
|
|
1253
1421
|
const command = args[0];
|
|
1254
1422
|
|
|
1255
1423
|
// Check if ABAP integration is enabled for this repo
|
|
1256
|
-
// (skip for init, help commands)
|
|
1257
|
-
|
|
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)) {
|
|
1258
1427
|
if (!isAbapIntegrationEnabled()) {
|
|
1259
1428
|
console.log(`
|
|
1260
1429
|
⚠️ ABAP Git Agent not configured for this repository.
|
|
@@ -1278,7 +1447,7 @@ To enable integration:
|
|
|
1278
1447
|
}
|
|
1279
1448
|
|
|
1280
1449
|
// Version compatibility check for commands that interact with ABAP
|
|
1281
|
-
const abapCommands = ['create', 'import', 'pull', 'inspect', 'unit', 'tree', 'view', 'preview'];
|
|
1450
|
+
const abapCommands = ['create', 'import', 'pull', 'inspect', 'unit', 'tree', 'view', 'preview', 'list'];
|
|
1282
1451
|
if (command && abapCommands.includes(command)) {
|
|
1283
1452
|
await checkVersionCompatibility();
|
|
1284
1453
|
}
|
|
@@ -1581,7 +1750,7 @@ Examples:
|
|
|
1581
1750
|
const packageArgIndex = args.indexOf('--package');
|
|
1582
1751
|
if (packageArgIndex === -1) {
|
|
1583
1752
|
console.error('Error: --package parameter required');
|
|
1584
|
-
console.error('Usage: abapgit-agent tree --package <package> [--depth <n>] [--include-
|
|
1753
|
+
console.error('Usage: abapgit-agent tree --package <package> [--depth <n>] [--include-types] [--json]');
|
|
1585
1754
|
console.error('Example: abapgit-agent tree --package ZMY_PACKAGE');
|
|
1586
1755
|
process.exit(1);
|
|
1587
1756
|
}
|
|
@@ -1595,7 +1764,7 @@ Examples:
|
|
|
1595
1764
|
console.error(' or escape the $ character:');
|
|
1596
1765
|
console.error(' abapgit-agent tree --package \\$ZMY_PACKAGE');
|
|
1597
1766
|
console.error('');
|
|
1598
|
-
console.error('Usage: abapgit-agent tree --package <package> [--depth <n>] [--include-
|
|
1767
|
+
console.error('Usage: abapgit-agent tree --package <package> [--depth <n>] [--include-types] [--json]');
|
|
1599
1768
|
console.error('Example: abapgit-agent tree --package ZMY_PACKAGE');
|
|
1600
1769
|
process.exit(1);
|
|
1601
1770
|
}
|
|
@@ -1605,7 +1774,7 @@ Examples:
|
|
|
1605
1774
|
// Check for empty/whitespace-only package name
|
|
1606
1775
|
if (!packageName || packageName.trim() === '') {
|
|
1607
1776
|
console.error('Error: --package parameter cannot be empty');
|
|
1608
|
-
console.error('Usage: abapgit-agent tree --package <package> [--depth <n>] [--include-
|
|
1777
|
+
console.error('Usage: abapgit-agent tree --package <package> [--depth <n>] [--include-types] [--json]');
|
|
1609
1778
|
console.error('Example: abapgit-agent tree --package ZMY_PACKAGE');
|
|
1610
1779
|
process.exit(1);
|
|
1611
1780
|
}
|
|
@@ -1621,8 +1790,8 @@ Examples:
|
|
|
1621
1790
|
}
|
|
1622
1791
|
}
|
|
1623
1792
|
|
|
1624
|
-
// Optional include-objects
|
|
1625
|
-
const
|
|
1793
|
+
// Optional include-types parameter (--include-objects is deprecated alias)
|
|
1794
|
+
const includeTypes = args.includes('--include-types') || args.includes('--include-objects');
|
|
1626
1795
|
|
|
1627
1796
|
// Optional json parameter
|
|
1628
1797
|
const jsonOutput = args.includes('--json');
|
|
@@ -1630,10 +1799,141 @@ Examples:
|
|
|
1630
1799
|
if (jsonOutput) {
|
|
1631
1800
|
const config = loadConfig();
|
|
1632
1801
|
const csrfToken = await fetchCsrfToken(config);
|
|
1633
|
-
const result = await runTreeCommand(packageName, depth,
|
|
1802
|
+
const result = await runTreeCommand(packageName, depth, includeTypes, csrfToken, config);
|
|
1634
1803
|
console.log(JSON.stringify(result, null, 2));
|
|
1635
1804
|
} else {
|
|
1636
|
-
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
|
+
}
|
|
1637
1937
|
}
|
|
1638
1938
|
break;
|
|
1639
1939
|
}
|
|
@@ -1881,7 +2181,7 @@ Examples:
|
|
|
1881
2181
|
}
|
|
1882
2182
|
|
|
1883
2183
|
if (where) {
|
|
1884
|
-
data.where = where;
|
|
2184
|
+
data.where = convertDatesInWhereClause(where);
|
|
1885
2185
|
}
|
|
1886
2186
|
|
|
1887
2187
|
if (columns) {
|
|
@@ -2079,6 +2379,109 @@ Examples:
|
|
|
2079
2379
|
break;
|
|
2080
2380
|
}
|
|
2081
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
|
+
|
|
2082
2485
|
case 'help':
|
|
2083
2486
|
case '--help':
|
|
2084
2487
|
case '-h':
|
|
@@ -2091,6 +2494,8 @@ Usage:
|
|
|
2091
2494
|
Commands:
|
|
2092
2495
|
init --folder <folder> --package <package>
|
|
2093
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.
|
|
2094
2499
|
|
|
2095
2500
|
create
|
|
2096
2501
|
Create abapGit online repository in ABAP system.
|
|
@@ -2112,12 +2517,30 @@ Commands:
|
|
|
2112
2517
|
unit --files <file1>,<file2>,...
|
|
2113
2518
|
Run AUnit tests for ABAP test class files (.testclasses.abap)
|
|
2114
2519
|
|
|
2115
|
-
tree --package <package> [--depth <n>] [--include-
|
|
2520
|
+
tree --package <package> [--depth <n>] [--include-types] [--json]
|
|
2116
2521
|
Display package hierarchy tree from ABAP system
|
|
2117
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
|
+
|
|
2118
2526
|
view --objects <obj1>,<obj2>,... [--type <type>] [--json]
|
|
2119
2527
|
View ABAP object definitions from the ABAP system
|
|
2120
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
|
+
|
|
2121
2544
|
health
|
|
2122
2545
|
Check if ABAP REST API is healthy
|
|
2123
2546
|
|
|
@@ -2126,6 +2549,7 @@ Commands:
|
|
|
2126
2549
|
|
|
2127
2550
|
Examples:
|
|
2128
2551
|
abapgit-agent init --folder /src --package ZMY_PACKAGE # Initialize
|
|
2552
|
+
abapgit-agent init --update # Update files to latest
|
|
2129
2553
|
abapgit-agent create # Create repo
|
|
2130
2554
|
abapgit-agent import # Import objects to git
|
|
2131
2555
|
abapgit-agent import --message "Initial import" # Import with message
|
|
@@ -2135,14 +2559,27 @@ Examples:
|
|
|
2135
2559
|
abapgit-agent pull --transport DEVK900001 # With transport
|
|
2136
2560
|
abapgit-agent inspect --files zcl_my_class.clas.abap # Syntax check
|
|
2137
2561
|
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
|
|
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
|
|
2142
2571
|
abapgit-agent view --objects ZCL_MY_CLASS # View class definition
|
|
2143
2572
|
abapgit-agent view --objects ZIF_MY_INTERFACE --type INTF # View interface
|
|
2144
2573
|
abapgit-agent view --objects ZMY_TABLE --type TABL # View table structure
|
|
2145
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
|
|
2146
2583
|
abapgit-agent health
|
|
2147
2584
|
abapgit-agent status
|
|
2148
2585
|
`);
|