abapgit-agent 1.9.0 → 1.10.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 +22 -0
- package/abap/CLAUDE.md +104 -72
- package/bin/abapgit-agent +1 -0
- package/package.json +6 -1
- package/src/commands/debug.js +1390 -0
- package/src/utils/adt-http.js +344 -0
- package/src/utils/debug-daemon.js +207 -0
- package/src/utils/debug-render.js +69 -0
- package/src/utils/debug-repl.js +256 -0
- package/src/utils/debug-session.js +845 -0
- package/src/utils/debug-state.js +124 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Debug session state persistence for AI / scripting mode.
|
|
5
|
+
* Saves active session ID to a tmp file so individual stateless sub-commands
|
|
6
|
+
* (debug step, debug vars, debug stack, debug terminate) can share session state
|
|
7
|
+
* without requiring --session on every call.
|
|
8
|
+
*
|
|
9
|
+
* Also provides breakpoint state persistence so that the full breakpoint list
|
|
10
|
+
* can be maintained locally (required for PUT/synchronize model of ADT API).
|
|
11
|
+
*/
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
const os = require('os');
|
|
15
|
+
const crypto = require('crypto');
|
|
16
|
+
|
|
17
|
+
function _stateFile(config) {
|
|
18
|
+
const hash = crypto.createHash('md5')
|
|
19
|
+
.update(`${config.host}:${config.user}:${config.client}`)
|
|
20
|
+
.digest('hex')
|
|
21
|
+
.substring(0, 8);
|
|
22
|
+
return path.join(os.tmpdir(), `abapgit-debug-active-${hash}.json`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function _bpStateFile(config) {
|
|
26
|
+
const hash = crypto.createHash('md5')
|
|
27
|
+
.update(`${config.host}:${config.user}:${config.client}`)
|
|
28
|
+
.digest('hex')
|
|
29
|
+
.substring(0, 8);
|
|
30
|
+
return path.join(os.tmpdir(), `abapgit-bpstate-${hash}.json`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Return the deterministic Unix socket path for the debug daemon.
|
|
35
|
+
* Computed from config so both cmdAttach and cmdStep can derive it independently.
|
|
36
|
+
* @param {object} config - ABAP connection config
|
|
37
|
+
* @returns {string}
|
|
38
|
+
*/
|
|
39
|
+
function getDaemonSocketPath(config) {
|
|
40
|
+
const hash = crypto.createHash('md5')
|
|
41
|
+
.update(`${config.host}:${config.user}:${config.client}`)
|
|
42
|
+
.digest('hex')
|
|
43
|
+
.substring(0, 8);
|
|
44
|
+
return path.join(os.tmpdir(), `abapgit-debug-daemon-${hash}.sock`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Persist the current list of breakpoints to a local tmp file.
|
|
49
|
+
* @param {object} config - ABAP connection config
|
|
50
|
+
* @param {Array} bps - Array of { id, object, uri, line, enabled }
|
|
51
|
+
*/
|
|
52
|
+
function saveBreakpointState(config, bps) {
|
|
53
|
+
try {
|
|
54
|
+
fs.writeFileSync(_bpStateFile(config), JSON.stringify({ breakpoints: bps, savedAt: Date.now() }), 'utf8');
|
|
55
|
+
} catch (e) {
|
|
56
|
+
// Non-fatal
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Load the locally-persisted breakpoint list.
|
|
62
|
+
* @param {object} config - ABAP connection config
|
|
63
|
+
* @returns {Array} Array of breakpoint objects (may be empty)
|
|
64
|
+
*/
|
|
65
|
+
function loadBreakpointState(config) {
|
|
66
|
+
const file = _bpStateFile(config);
|
|
67
|
+
if (!fs.existsSync(file)) return [];
|
|
68
|
+
try {
|
|
69
|
+
const data = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
70
|
+
return Array.isArray(data.breakpoints) ? data.breakpoints : [];
|
|
71
|
+
} catch (e) {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Persist the active debug session after a successful attach.
|
|
78
|
+
* @param {object} config - ABAP connection config
|
|
79
|
+
* @param {object} state - { sessionId, position }
|
|
80
|
+
*/
|
|
81
|
+
function saveActiveSession(config, state) {
|
|
82
|
+
try {
|
|
83
|
+
fs.writeFileSync(_stateFile(config), JSON.stringify({ ...state, savedAt: Date.now() }), 'utf8');
|
|
84
|
+
} catch (e) {
|
|
85
|
+
// Non-fatal — AI mode will require --session explicitly if file can't be written
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Load the active debug session saved by a previous attach.
|
|
91
|
+
* @param {object} config - ABAP connection config
|
|
92
|
+
* @returns {{ sessionId: string, position: object }|null} Session state or null
|
|
93
|
+
*/
|
|
94
|
+
function loadActiveSession(config) {
|
|
95
|
+
const file = _stateFile(config);
|
|
96
|
+
if (!fs.existsSync(file)) return null;
|
|
97
|
+
try {
|
|
98
|
+
return JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
99
|
+
} catch (e) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Mark the active session as ended.
|
|
106
|
+
*
|
|
107
|
+
* Writes { sessionId: null } rather than deleting the file so that any other
|
|
108
|
+
* process polling in takeover mode can detect the cleared state immediately,
|
|
109
|
+
* even when it is currently handling a non-empty (breakpoint-hit) ADT response.
|
|
110
|
+
* Checking !currentSession.sessionId covers both "file deleted" (null object)
|
|
111
|
+
* and "file present but sessionId is null".
|
|
112
|
+
*
|
|
113
|
+
* @param {object} config - ABAP connection config
|
|
114
|
+
*/
|
|
115
|
+
function clearActiveSession(config) {
|
|
116
|
+
try {
|
|
117
|
+
const file = _stateFile(config);
|
|
118
|
+
fs.writeFileSync(file, JSON.stringify({ sessionId: null, clearedAt: Date.now() }), 'utf8');
|
|
119
|
+
} catch (e) {
|
|
120
|
+
// Ignore
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
module.exports = { saveActiveSession, loadActiveSession, clearActiveSession, saveBreakpointState, loadBreakpointState, getDaemonSocketPath };
|