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.
@@ -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 };