abapgit-agent 1.11.4 → 1.12.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/abap/CLAUDE.md CHANGED
@@ -225,7 +225,23 @@ abapgit-agent unit --files src/zcl_test1.clas.testclasses.abap,src/zcl_test2.cla
225
225
 
226
226
  ---
227
227
 
228
- ### 9. Troubleshooting ABAP Issues
228
+ ### 9. Never Run `run` Command Proactively
229
+
230
+ **Never call `abapgit-agent run` unless the user explicitly asks.** A class implementing `IF_OO_ADT_CLASSRUN` can modify data, send emails, or trigger RFCs — running it automatically is unsafe.
231
+
232
+ After activating a class, stop and tell the user: `"Class is activated. Run with: abapgit-agent run --class ZCL_MY_CLASS"`
233
+
234
+ ---
235
+
236
+ ### 10. Probe Classes — Use `scratchWorkspace` When Required
237
+
238
+ By default, probe/throwaway classes may be created in the current project. When `disableProbeClasses: true` is set in `.abapgit-agent.json`, they must go to `scratchWorkspace` instead. If `scratchWorkspace` is also not configured, refuse and guide the user to set it up.
239
+
240
+ → See `guidelines/run-probe-classes.md` for naming conventions, full workflow, and refusal guidance
241
+
242
+ ---
243
+
244
+ ### 11. Troubleshooting ABAP Issues
229
245
 
230
246
  | Symptom | Tool | When |
231
247
  |---|---|---|
@@ -236,6 +252,7 @@ Quick start:
236
252
  ```bash
237
253
  abapgit-agent dump --date TODAY --detail 1 # inspect last crash
238
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
239
256
  ```
240
257
  → See `guidelines/debug-dump.md` for dump analysis workflow
241
258
  → See `guidelines/debug-session.md` for full debug session guide, breakpoint tips, and pull flow architecture
@@ -326,6 +343,13 @@ abapgit-agent pull --files src/zcl_auth_handler.clas.abap
326
343
  1. ✗ Do not run `abapgit-agent pull` at all
327
344
  2. ✓ Inform the user that pull is disabled for this project (CI/CD only)
328
345
 
346
+ **When `safeguards.disableRun = true`:**
347
+ 1. ✗ Do not run `abapgit-agent run` at all
348
+ 2. ✓ Inform the user that run is disabled for this project
349
+
350
+ **When `safeguards.disableProbeClasses = true`:**
351
+ 1. ✗ Do not create probe classes in the current project — see Rule 10 and `guidelines/run-command.md`
352
+
329
353
  **When `conflictDetection.mode = "ignore"` or not set:**
330
354
  1. ✓ Run `pull` normally — no conflict flags needed
331
355
  2. ✗ Don't add `--conflict-mode` unless user explicitly asks
@@ -384,6 +408,7 @@ Detailed guidelines are available in the `guidelines/` folder:
384
408
  | `guidelines/common-errors.md` | Common ABAP Errors - Quick Fixes |
385
409
  | `guidelines/debug-session.md` | Debug Session Guide |
386
410
  | `guidelines/debug-dump.md` | Dump Analysis Guide |
411
+ | `guidelines/run-probe-classes.md` | run Command — AI Guidelines (probe classes, scratchWorkspace) |
387
412
  | `guidelines/branch-workflow.md` | Branch Workflow |
388
413
  | `guidelines/workflow-detailed.md` | Development Workflow (Detailed) |
389
414
  | `guidelines/object-creation.md` | Object Creation (XML metadata, local classes) |
@@ -166,7 +166,7 @@ abapgit-agent debug stack --json # call stack (shows whi
166
166
  abapgit-agent debug delete --all
167
167
  ```
168
168
 
169
- > **If the stale debug daemon holds an ABAP lock** (symptom: `Requested object EZABAPGIT is currently locked by user CAIS`):
169
+ > **If the stale debug daemon holds an ABAP lock** (symptom: `Requested object EZABAPGIT is currently locked by user <USER>`):
170
170
  > ```bash
171
171
  > pkill -f "debug-daemon" # kills daemon, SIGTERM triggers session.terminate() internally
172
172
  > ```
@@ -0,0 +1,67 @@
1
+ ---
2
+ layout: default
3
+ title: run Command Guide
4
+ nav_order: 18
5
+ parent: ABAP Coding Guidelines
6
+ grand_parent: ABAP Development
7
+ ---
8
+
9
+ # run Command — AI Guidelines
10
+
11
+ ## Never Run Proactively
12
+
13
+ `abapgit-agent run` executes live ABAP code. **Never call it unless the user explicitly asks.**
14
+
15
+ A class implementing `IF_OO_ADT_CLASSRUN` can do anything — modify database records, send emails, trigger RFCs. The interface signature gives no indication of side effects.
16
+
17
+ ```
18
+ User: "Write a class that reads flight data and prints it"
19
+ → ✓ Create the class, pull it, STOP. Do NOT run it.
20
+ → ✓ Tell the user: "Class is activated. Run with: abapgit-agent run --class ZCL_MY_CLASS"
21
+
22
+ User: "Now run it"
23
+ → ✓ Run it
24
+ ```
25
+
26
+ ---
27
+
28
+ ## Probe Classes and `scratchWorkspace`
29
+
30
+ ### Decision flow
31
+
32
+ ```
33
+ User asks to create a probe class
34
+ ├── disableProbeClasses = false / not set → create in current project (default)
35
+ └── disableProbeClasses = true
36
+ ├── scratchWorkspace configured → create there (see workflow below)
37
+ └── scratchWorkspace not configured → refuse, guide user to set it up
38
+ ```
39
+
40
+ ### When `disableProbeClasses = true` and `scratchWorkspace` is configured
41
+
42
+ **Naming** — derive from `scratchWorkspace` config in `.abapGitAgent`:
43
+ - `classPrefix` (default: `ZCL_{USER}_`) + `<PURPOSE>`, max 30 chars
44
+ - Example: user=`JOHN`, purpose=`OPEN_TRANSPORTS` → `ZCL_JOHN_OPEN_TRANSPORTS`
45
+ - If name already exists in `{path}/src/`, append `_2`, `_3`, etc.
46
+
47
+ **Workflow:**
48
+ 1. Read `{path}/.abapGitAgent` to confirm `folder` property (e.g. `/src/`)
49
+ 2. Write class files in `{path}/src/`
50
+ 3. Commit and push from `{path}`:
51
+ ```bash
52
+ cd {path} && git add . && git commit -m "probe: <description>" && git push
53
+ ```
54
+ 4. Activate:
55
+ ```bash
56
+ cd {path} && abapgit-agent pull --files src/<classname>.clas.abap
57
+ ```
58
+ 5. Tell user (do NOT auto-run):
59
+ ```
60
+ Class activated. Run with: abapgit-agent run --class <CLASSNAME>
61
+ ```
62
+ Run the command from the original project directory, not `{path}`.
63
+
64
+ ### When `disableProbeClasses = true` and `scratchWorkspace` is NOT configured
65
+
66
+ Refuse and tell the user to configure `scratchWorkspace` in `.abapGitAgent`.
67
+ → See `docs/run-command.md` (Scratch Workspace section) for setup instructions.
package/bin/abapgit-agent CHANGED
@@ -24,7 +24,7 @@ const gitUtils = require('../src/utils/git-utils');
24
24
  const versionCheck = require('../src/utils/version-check');
25
25
  const validators = require('../src/utils/validators');
26
26
  const { AbapHttp } = require('../src/utils/abap-http');
27
- const { loadConfig, getTransport, isAbapIntegrationEnabled, getSafeguards, getConflictSettings, getTransportSettings } = require('../src/config');
27
+ const { loadConfig, getTransport, isAbapIntegrationEnabled, getSafeguards, getConflictSettings, getTransportSettings, getScratchWorkspace } = require('../src/config');
28
28
 
29
29
  // Get terminal width for responsive table
30
30
  const getTermWidth = () => process.stdout.columns || 80;
@@ -52,6 +52,7 @@ async function main() {
52
52
  where: require('../src/commands/where'),
53
53
  dump: require('../src/commands/dump'),
54
54
  debug: require('../src/commands/debug'),
55
+ run: require('../src/commands/run'),
55
56
  ref: require('../src/commands/ref'),
56
57
  init: require('../src/commands/init'),
57
58
  pull: require('../src/commands/pull'),
@@ -105,7 +106,8 @@ To enable integration:
105
106
  getTransport,
106
107
  getSafeguards,
107
108
  getConflictSettings,
108
- getTransportSettings
109
+ getTransportSettings,
110
+ getScratchWorkspace
109
111
  };
110
112
 
111
113
  // Execute command
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "abapgit-agent",
3
- "version": "1.11.4",
3
+ "version": "1.12.0",
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": [
@@ -284,11 +284,9 @@ module.exports = {
284
284
 
285
285
  if (success === 'X' || success === true) {
286
286
  console.log(`✅ Pull completed successfully!`);
287
- console.log(` Job ID: ${jobId || 'N/A'}`);
288
287
  console.log(` Message: ${message || 'N/A'}`);
289
288
  } else {
290
289
  console.error(`❌ Pull completed with errors!`);
291
- console.error(` Job ID: ${jobId || 'N/A'}`);
292
290
  console.error(` Message: ${message || 'N/A'}`);
293
291
  }
294
292
 
@@ -0,0 +1,123 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * run command — Execute an ABAP program or class and display its output.
5
+ *
6
+ * Programs (--program):
7
+ * POST /sap/bc/adt/programs/programrun/{name}
8
+ * Content-Type: application/vnd.sap.adt.programs.programRun+xml
9
+ * Accept: text/plain
10
+ * Note: SAP's ADT handler (CL_SEDI_ADT_PROGRAMRUN) calls SUBMIT with no
11
+ * WITH additions — runtime parameters cannot be passed. The program
12
+ * always runs with its coded defaults.
13
+ *
14
+ * Classes (--class):
15
+ * POST /sap/bc/adt/oo/classrun/{name}
16
+ * Accept: text/plain
17
+ * Requires the class to implement IF_OO_ADT_CLASSRUN.
18
+ * out->write() output is returned as plain text.
19
+ */
20
+
21
+ const { AdtHttp } = require('../utils/adt-http');
22
+
23
+ const PROGRAM_RUN_XML =
24
+ '<?xml version="1.0" encoding="UTF-8"?>\n' +
25
+ '<adtprog:programRun xmlns:adtprog="http://www.sap.com/adt/programs/programs"/>';
26
+
27
+ module.exports = {
28
+ name: 'run',
29
+ description: 'Execute an ABAP program or class (IF_OO_ADT_CLASSRUN) and display its output',
30
+ requiresAbapConfig: true,
31
+ requiresVersionCheck: false,
32
+
33
+ async execute(args, context) {
34
+ const { loadConfig, getSafeguards } = context;
35
+
36
+ // Check project-level safeguards
37
+ const safeguards = getSafeguards();
38
+ if (safeguards.disableRun) {
39
+ console.error('❌ Error: run command is disabled for this project\n');
40
+ if (safeguards.reason) {
41
+ console.error(`Reason: ${safeguards.reason}\n`);
42
+ }
43
+ console.error('The run command has been disabled in .abapgit-agent.json');
44
+ console.error('Please contact the project maintainer to enable it.');
45
+ process.exit(1);
46
+ }
47
+
48
+ // Parse arguments
49
+ let programName = null;
50
+ let className = null;
51
+ let jsonOutput = false;
52
+
53
+ for (let i = 0; i < args.length; i++) {
54
+ if (args[i] === '--program' && args[i + 1]) {
55
+ programName = args[++i].toUpperCase();
56
+ } else if (args[i] === '--class' && args[i + 1]) {
57
+ className = args[++i].toUpperCase();
58
+ } else if (args[i] === '--json') {
59
+ jsonOutput = true;
60
+ }
61
+ }
62
+
63
+ if (programName && className) {
64
+ console.error('Error: --program and --class are mutually exclusive');
65
+ process.exit(1);
66
+ }
67
+
68
+ if (!programName && !className) {
69
+ console.error('Error: either --program or --class is required');
70
+ console.error('Usage: abapgit-agent run --program <NAME>');
71
+ console.error(' abapgit-agent run --class <NAME>');
72
+ process.exit(1);
73
+ }
74
+
75
+ const config = loadConfig();
76
+ const adt = new AdtHttp(config);
77
+
78
+ if (!adt.csrfToken) {
79
+ await adt.fetchCsrfToken();
80
+ }
81
+
82
+ let urlPath, body, requestOptions, targetName;
83
+
84
+ if (className) {
85
+ targetName = className;
86
+ urlPath = `/sap/bc/adt/oo/classrun/${className}`;
87
+ body = '';
88
+ requestOptions = { accept: 'text/plain' };
89
+ } else {
90
+ targetName = programName;
91
+ urlPath = `/sap/bc/adt/programs/programrun/${programName}`;
92
+ body = PROGRAM_RUN_XML;
93
+ requestOptions = {
94
+ contentType: 'application/vnd.sap.adt.programs.programRun+xml',
95
+ accept: 'text/plain'
96
+ };
97
+ }
98
+
99
+ let response;
100
+ try {
101
+ response = await adt.request('POST', urlPath, body, requestOptions);
102
+ } catch (err) {
103
+ if (jsonOutput) {
104
+ console.log(JSON.stringify({ success: false, target: targetName, error: err.message || String(err) }));
105
+ } else {
106
+ console.error(`Error: ${err.message || err}`);
107
+ }
108
+ process.exit(1);
109
+ }
110
+
111
+ const output = (response.body || '').trimEnd();
112
+
113
+ if (jsonOutput) {
114
+ const key = className ? 'class' : 'program';
115
+ console.log(JSON.stringify({ success: true, [key]: targetName, output }));
116
+ } else {
117
+ console.log('\n--- Output ---');
118
+ console.log(output || '(no output)');
119
+ console.log('--------------');
120
+ console.log(`✅ Completed: ${targetName}`);
121
+ }
122
+ }
123
+ };
package/src/config.js CHANGED
@@ -122,6 +122,8 @@ function getSafeguards() {
122
122
  return {
123
123
  requireFilesForPull: projectConfig.safeguards.requireFilesForPull === true,
124
124
  disablePull: projectConfig.safeguards.disablePull === true,
125
+ disableRun: projectConfig.safeguards.disableRun === true,
126
+ disableProbeClasses: projectConfig.safeguards.disableProbeClasses === true,
125
127
  reason: projectConfig.safeguards.reason || null
126
128
  };
127
129
  }
@@ -130,6 +132,8 @@ function getSafeguards() {
130
132
  return {
131
133
  requireFilesForPull: false,
132
134
  disablePull: false,
135
+ disableRun: false,
136
+ disableProbeClasses: false,
133
137
  reason: null
134
138
  };
135
139
  }
@@ -199,6 +203,22 @@ function getTransportSettings() {
199
203
  return { allowCreate: true, allowRelease: true, reason: null };
200
204
  }
201
205
 
206
+ /**
207
+ * Get scratch workspace configuration from personal config (.abapGitAgent)
208
+ * Used by AI to create probe/throwaway ABAP classes outside the current project
209
+ * @returns {{ path: string, classPrefix: string, programPrefix: string }|null}
210
+ */
211
+ function getScratchWorkspace() {
212
+ const cfg = loadConfig();
213
+ if (!cfg.scratchWorkspace) return null;
214
+ const user = (cfg.user || 'PROBE').toUpperCase();
215
+ return {
216
+ path: cfg.scratchWorkspace.path || null,
217
+ classPrefix: cfg.scratchWorkspace.classPrefix || `ZCL_${user}_`,
218
+ programPrefix: cfg.scratchWorkspace.programPrefix || `Z${user}_`
219
+ };
220
+ }
221
+
202
222
  module.exports = {
203
223
  loadConfig,
204
224
  getAbapConfig,
@@ -211,5 +231,6 @@ module.exports = {
211
231
  getConflictSettings,
212
232
  loadProjectConfig,
213
233
  getTransportHookConfig,
214
- getTransportSettings
234
+ getTransportSettings,
235
+ getScratchWorkspace
215
236
  };