abapgit-agent 1.12.0 → 1.12.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/abap/CLAUDE.md CHANGED
@@ -248,13 +248,27 @@ By default, probe/throwaway classes may be created in the current project. When
248
248
  | HTTP 500 / runtime crash (ST22) | `dump` | Error already occurred |
249
249
  | Wrong output, no crash | `debug` | Need to trace logic |
250
250
 
251
- Quick start:
251
+ See `guidelines/debug-dump.md` for dump analysis workflow
252
+
253
+ **Critical rules for `debug` sessions:**
254
+
255
+ 1. **Always use `--json`** for all debug commands (`attach`, `vars`, `stack`, `step`) — human output is not machine-parseable
256
+ 2. **Attach BEFORE trigger** — start `debug attach --json` in background first, wait for `"Listener active"`, THEN fire the trigger (`unit`/`pull`/`run`)
257
+ 3. **Never pull to trigger** if a simpler trigger works — use `unit` when a test exists, `run` for a class runner; use `pull` only when the bug is specifically in the pull flow
258
+ 4. **Never pass `--session`** to `step/vars/stack` — it bypasses the daemon and causes errors
259
+ 5. **Always finish with `step --type continue --json`** — releases the frozen ABAP work process
260
+
261
+ Minimal correct sequence:
252
262
  ```bash
253
- abapgit-agent dump --date TODAY --detail 1 # inspect last crash
254
- abapgit-agent debug set --objects ZCL_FOO:42 # set breakpoint then attach
255
- abapgit-agent run --class ZCL_MY_RUNNER # execute and inspect output
263
+ abapgit-agent debug set --objects ZCL_FOO:42 # 1. set breakpoint
264
+ abapgit-agent debug attach --json > /tmp/a.json 2>&1 & # 2. attach (background)
265
+ until grep -q "Listener active" /tmp/a.json 2>/dev/null; do sleep 0.3; done
266
+ abapgit-agent unit --files src/zcl_foo.clas.testclasses.abap > /tmp/t.json 2>&1 & # 3. trigger
267
+ # poll for session, then inspect
268
+ abapgit-agent debug vars --json
269
+ abapgit-agent debug step --type continue --json # 4. release
256
270
  ```
257
- → See `guidelines/debug-dump.md` for dump analysis workflow
271
+
258
272
  → See `guidelines/debug-session.md` for full debug session guide, breakpoint tips, and pull flow architecture
259
273
 
260
274
  ---
@@ -363,6 +377,12 @@ abapgit-agent pull --files src/zcl_auth_handler.clas.abap
363
377
  1. ✗ Do not run `abapgit-agent transport create`
364
378
  2. ✓ Inform the user that transport creation is disabled for this project
365
379
 
380
+ **When pull result contains `missing_abapgit_xml: true` (JSON mode) or warning about `.abapgit.xml`:**
381
+ 1. ✓ Inform the user that `.abapgit.xml` is missing from the repository root
382
+ 2. ✓ Suggest running `abapgit-agent init --package <PACKAGE>` to create it
383
+ 3. ✓ If `ACTIVATED_COUNT=0` with an empty log, suspect this as the cause
384
+ 4. ✗ Do not retry the pull — fix the missing file first
385
+
366
386
  **When `transports.allowRelease = false`:**
367
387
  1. ✗ Do not run `abapgit-agent transport release`
368
388
  2. ✓ Inform the user that transport release is disabled for this project
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "abapgit-agent",
3
- "version": "1.12.0",
3
+ "version": "1.12.1",
4
4
  "description": "ABAP Git Agent - Pull and activate ABAP code via abapGit from any git repository",
5
5
  "main": "src/index.js",
6
6
  "files": [
@@ -129,7 +129,7 @@ Usage:
129
129
 
130
130
  Description:
131
131
  Initialize local repository configuration.
132
- Creates .abapGitAgent, .gitignore, CLAUDE.md, and guidelines folder.
132
+ Creates .abapGitAgent, .abapgit.xml, .gitignore, CLAUDE.md, and guidelines folder.
133
133
 
134
134
  Options:
135
135
  --package <PACKAGE> ABAP package name (required)
@@ -500,6 +500,34 @@ Uncomment and edit the rows that differ from the defaults in \`guidelines/object
500
500
  console.error(`Error creating folder: ${error.message}`);
501
501
  }
502
502
 
503
+ // Create .abapgit.xml with correct STARTING_FOLDER so abapGit's remove_ignored_files()
504
+ // keeps files inside the source folder. Without this file the stored starting_folder in
505
+ // the ABAP persistence may not match the actual folder, causing all remote files to be
506
+ // silently ignored and pull to return ACTIVATED_COUNT=0 with an empty log.
507
+ const abapgitXmlPath = pathModule.join(process.cwd(), '.abapgit.xml');
508
+ if (!fs.existsSync(abapgitXmlPath)) {
509
+ const language = (config.language || 'E').toUpperCase().charAt(0);
510
+ const abapgitXml = `<?xml version="1.0" encoding="utf-8"?>
511
+ <asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
512
+ <asx:values>
513
+ <DATA>
514
+ <MASTER_LANGUAGE>${language}</MASTER_LANGUAGE>
515
+ <STARTING_FOLDER>${folder}</STARTING_FOLDER>
516
+ <FOLDER_LOGIC>${folderLogic}</FOLDER_LOGIC>
517
+ </DATA>
518
+ </asx:values>
519
+ </asx:abap>
520
+ `;
521
+ try {
522
+ fs.writeFileSync(abapgitXmlPath, abapgitXml);
523
+ console.log(`✅ Created .abapgit.xml (STARTING_FOLDER=${folder}, FOLDER_LOGIC=${folderLogic})`);
524
+ } catch (error) {
525
+ console.error(`Error creating .abapgit.xml: ${error.message}`);
526
+ }
527
+ } else {
528
+ console.log(`✅ .abapgit.xml already exists, skipped`);
529
+ }
530
+
503
531
  console.log(`
504
532
  📋 Next steps:
505
533
  1. Edit .abapGitAgent with your ABAP credentials (host, user, password)
@@ -3,6 +3,8 @@
3
3
  */
4
4
 
5
5
  const { printHttpError } = require('../utils/format-error');
6
+ const fs = require('fs');
7
+ const pathModule = require('path');
6
8
 
7
9
  module.exports = {
8
10
  name: 'pull',
@@ -84,6 +86,20 @@ module.exports = {
84
86
  console.error(' Example: --files src/zcl_my_class.clas.abap');
85
87
  process.exit(1);
86
88
  }
89
+
90
+ // Validate that every specified file exists on disk.
91
+ // Skip when --url is explicit: the files belong to a different repository
92
+ // and won't be present in the current working directory.
93
+ if (urlArgIndex === -1) {
94
+ const fs = require('fs');
95
+ const missingFiles = files.filter(f => !fs.existsSync(f));
96
+ if (missingFiles.length > 0) {
97
+ console.error('❌ Error: the following file(s) do not exist:');
98
+ missingFiles.forEach(f => console.error(` ${f}`));
99
+ console.error(' Check the path and try again.');
100
+ process.exit(1);
101
+ }
102
+ }
87
103
  }
88
104
 
89
105
  // SAFEGUARD 2: Check if files are required but not provided
@@ -102,22 +118,30 @@ module.exports = {
102
118
  if (!transportRequest && !jsonOutput) {
103
119
  const { selectTransport, isNonInteractive, _getTransportHookConfig } = require('../utils/transport-selector');
104
120
 
105
- // Check if this package requires a transport before showing the interactive
106
- // picker. Skip the status round-trip in non-interactive mode — selectTransport
107
- // already returns null there without prompting, so the extra HTTP call is wasted.
108
- let transportRequired = true; // Safe default: assume transport needed
109
- if (!isNonInteractive()) {
110
- try {
111
- const config = loadConfig();
112
- const http = new AbapHttp(config);
113
- const csrfToken = await http.fetchCsrfToken();
114
- const statusResult = await http.post('/sap/bc/z_abapgit_agent/status', { url: gitUrl }, { csrfToken });
115
- if (statusResult.transport_required === false || statusResult.transport_required === 'false') {
116
- transportRequired = false;
117
- }
118
- } catch (e) {
119
- // Status check failed — proceed with selector as safe default
120
- }
121
+ // Check repository status confirms the repo is registered and tells us
122
+ // whether a transport is required. If the check fails, abort: pulling into
123
+ // an uninitialised repository does not make sense.
124
+ let transportRequired = false;
125
+ let statusResult;
126
+ try {
127
+ const config = loadConfig();
128
+ const http = new AbapHttp(config);
129
+ const csrfToken = await http.fetchCsrfToken();
130
+ statusResult = await http.post('/sap/bc/z_abapgit_agent/status', { url: gitUrl }, { csrfToken });
131
+ } catch (e) {
132
+ console.error(`❌ Repository status check failed: ${e.message}`);
133
+ console.error(' Make sure the repository is registered with abapgit-agent (run "abapgit-agent create").');
134
+ process.exit(1);
135
+ }
136
+
137
+ if (!statusResult || statusResult.status === 'Not found') {
138
+ console.error(`❌ Repository not found in ABAP system: ${gitUrl}`);
139
+ console.error(' Run "abapgit-agent create" to register it first.');
140
+ process.exit(1);
141
+ }
142
+
143
+ if (statusResult.transport_required === true || statusResult.transport_required === 'true') {
144
+ transportRequired = true;
121
145
  }
122
146
 
123
147
  if (transportRequired) {
@@ -147,10 +171,10 @@ module.exports = {
147
171
  }
148
172
  }
149
173
 
150
- await this.pull(gitUrl, branch, files, transportRequest, loadConfig, AbapHttp, jsonOutput, undefined, conflictMode);
174
+ await this.pull(gitUrl, branch, files, transportRequest, loadConfig, AbapHttp, jsonOutput, undefined, conflictMode, verbose);
151
175
  },
152
176
 
153
- async pull(gitUrl, branch = 'main', files = null, transportRequest = null, loadConfig, AbapHttp, jsonOutput = false, gitCredentials = undefined, conflictMode = 'abort') {
177
+ async pull(gitUrl, branch = 'main', files = null, transportRequest = null, loadConfig, AbapHttp, jsonOutput = false, gitCredentials = undefined, conflictMode = 'abort', verbose = false) {
154
178
  const TERM_WIDTH = process.stdout.columns || 80;
155
179
 
156
180
  if (!jsonOutput) {
@@ -196,12 +220,26 @@ module.exports = {
196
220
 
197
221
  const result = await http.post('/sap/bc/z_abapgit_agent/pull', data, { csrfToken });
198
222
 
223
+ // Detect missing .abapgit.xml — without it abapGit's stored starting_folder
224
+ // may not match the actual source folder, causing pull to silently return ACTIVATED_COUNT=0
225
+ const missingAbapgitXml = fs.existsSync(pathModule.join(process.cwd(), '.git')) &&
226
+ !fs.existsSync(pathModule.join(process.cwd(), '.abapgit.xml'));
227
+
199
228
  // JSON output mode
200
229
  if (jsonOutput) {
230
+ if (missingAbapgitXml) {
231
+ result.missing_abapgit_xml = true;
232
+ }
201
233
  console.log(JSON.stringify(result, null, 2));
202
234
  return result;
203
235
  }
204
236
 
237
+ if (missingAbapgitXml) {
238
+ console.warn('⚠️ .abapgit.xml not found in repository root.');
239
+ console.warn(' Pull may return ACTIVATED_COUNT=0 if the ABAP-side starting_folder is wrong.');
240
+ console.warn(' Run: abapgit-agent init --package <PACKAGE> to create it.\n');
241
+ }
242
+
205
243
  console.log('\n');
206
244
 
207
245
  // Display raw result for debugging