@gowelle/stint-agent 1.1.0 → 1.2.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,369 @@
1
+ import {
2
+ apiService
3
+ } from "./chunk-W4JGOGR7.js";
4
+ import {
5
+ gitService,
6
+ projectService
7
+ } from "./chunk-FBQA4K5J.js";
8
+ import {
9
+ authService,
10
+ config,
11
+ logger
12
+ } from "./chunk-RHMTZK2J.js";
13
+
14
+ // src/daemon/queue.ts
15
+ var CommitQueueProcessor = class {
16
+ queue = [];
17
+ isProcessing = false;
18
+ /**
19
+ * Add commit to processing queue
20
+ */
21
+ addToQueue(commit, project) {
22
+ this.queue.push({ commit, project });
23
+ logger.info("queue", `Added commit ${commit.id} to queue (position: ${this.queue.length})`);
24
+ if (!this.isProcessing) {
25
+ this.processQueue();
26
+ }
27
+ }
28
+ /**
29
+ * Process commits sequentially
30
+ */
31
+ async processQueue() {
32
+ if (this.isProcessing) {
33
+ return;
34
+ }
35
+ this.isProcessing = true;
36
+ while (this.queue.length > 0) {
37
+ const item = this.queue.shift();
38
+ if (!item) break;
39
+ try {
40
+ await this.executeCommit(item.commit, item.project);
41
+ } catch (error) {
42
+ logger.error("queue", `Failed to execute commit ${item.commit.id}`, error);
43
+ }
44
+ }
45
+ this.isProcessing = false;
46
+ }
47
+ /**
48
+ * Execute a single commit
49
+ */
50
+ async executeCommit(commit, project, onProgress) {
51
+ logger.info("queue", `Processing commit: ${commit.id} - ${commit.message}`);
52
+ try {
53
+ onProgress?.("Finding project directory...");
54
+ const projectPath = this.findProjectPath(project.id);
55
+ if (!projectPath) {
56
+ throw new Error(`Project ${project.id} is not linked to any local directory`);
57
+ }
58
+ logger.info("queue", `Executing in directory: ${projectPath}`);
59
+ onProgress?.("Validating repository...");
60
+ const isRepo = await gitService.isRepo(projectPath);
61
+ if (!isRepo) {
62
+ throw new Error(`Directory ${projectPath} is not a git repository`);
63
+ }
64
+ onProgress?.("Checking repository status...");
65
+ const status = await gitService.getStatus(projectPath);
66
+ const hasStagedChanges = status.staged.length > 0;
67
+ if (!hasStagedChanges) {
68
+ throw new Error('No staged changes to commit. Please stage files using "git add" before committing.');
69
+ }
70
+ logger.info("queue", `Committing ${status.staged.length} staged files.`);
71
+ onProgress?.("Creating commit...");
72
+ logger.info("queue", `Creating commit with message: "${commit.message}"`);
73
+ const sha = await gitService.commit(projectPath, commit.message);
74
+ logger.success("queue", `Commit created successfully: ${sha}`);
75
+ onProgress?.("Reporting to server...");
76
+ await this.reportSuccess(commit.id, sha);
77
+ return sha;
78
+ } catch (error) {
79
+ const errorMessage = error.message;
80
+ logger.error("queue", `Commit execution failed: ${errorMessage}`);
81
+ await this.reportFailure(commit.id, errorMessage);
82
+ throw error;
83
+ }
84
+ }
85
+ /**
86
+ * Report successful execution to API
87
+ */
88
+ async reportSuccess(commitId, sha) {
89
+ try {
90
+ await apiService.markCommitExecuted(commitId, sha);
91
+ logger.success("queue", `Reported commit execution to API: ${commitId} -> ${sha}`);
92
+ } catch (error) {
93
+ logger.error("queue", "Failed to report commit success to API", error);
94
+ }
95
+ }
96
+ /**
97
+ * Report failed execution to API
98
+ */
99
+ async reportFailure(commitId, error) {
100
+ try {
101
+ await apiService.markCommitFailed(commitId, error);
102
+ logger.info("queue", `Reported commit failure to API: ${commitId}`);
103
+ } catch (apiError) {
104
+ logger.error("queue", "Failed to report commit failure to API", apiError);
105
+ }
106
+ }
107
+ /**
108
+ * Find local path for a project ID
109
+ */
110
+ findProjectPath(projectId) {
111
+ const allProjects = projectService.getAllLinkedProjects();
112
+ for (const [path, linkedProject] of Object.entries(allProjects)) {
113
+ if (linkedProject.projectId === projectId) {
114
+ return path;
115
+ }
116
+ }
117
+ return null;
118
+ }
119
+ /**
120
+ * Check if queue is currently processing
121
+ */
122
+ isCurrentlyProcessing() {
123
+ return this.isProcessing;
124
+ }
125
+ /**
126
+ * Get queue length
127
+ */
128
+ getQueueLength() {
129
+ return this.queue.length;
130
+ }
131
+ };
132
+ var commitQueue = new CommitQueueProcessor();
133
+
134
+ // src/services/websocket.ts
135
+ import WebSocket from "ws";
136
+ var WebSocketServiceImpl = class {
137
+ ws = null;
138
+ userId = null;
139
+ reconnectAttempts = 0;
140
+ maxReconnectAttempts = 10;
141
+ reconnectTimer = null;
142
+ isManualDisconnect = false;
143
+ // Event handlers
144
+ commitApprovedHandlers = [];
145
+ commitPendingHandlers = [];
146
+ suggestionCreatedHandlers = [];
147
+ projectUpdatedHandlers = [];
148
+ disconnectHandlers = [];
149
+ agentDisconnectedHandlers = [];
150
+ syncRequestedHandlers = [];
151
+ /**
152
+ * Connect to the WebSocket server
153
+ * @throws Error if connection fails or no auth token available
154
+ */
155
+ async connect() {
156
+ try {
157
+ const token = await authService.getToken();
158
+ if (!token) {
159
+ throw new Error("No authentication token available");
160
+ }
161
+ const wsUrl = config.getWsUrl();
162
+ const url = `${wsUrl}?token=${encodeURIComponent(token)}`;
163
+ logger.info("websocket", `Connecting to ${wsUrl}...`);
164
+ this.ws = new WebSocket(url);
165
+ return new Promise((resolve, reject) => {
166
+ if (!this.ws) {
167
+ reject(new Error("WebSocket not initialized"));
168
+ return;
169
+ }
170
+ this.ws.on("open", () => {
171
+ logger.success("websocket", "WebSocket connected");
172
+ this.reconnectAttempts = 0;
173
+ this.isManualDisconnect = false;
174
+ resolve();
175
+ });
176
+ this.ws.on("message", (data) => {
177
+ this.handleMessage(data);
178
+ });
179
+ this.ws.on("close", () => {
180
+ logger.warn("websocket", "WebSocket disconnected");
181
+ this.handleDisconnect();
182
+ });
183
+ this.ws.on("error", (error) => {
184
+ logger.error("websocket", "WebSocket error", error);
185
+ reject(error);
186
+ });
187
+ });
188
+ } catch (error) {
189
+ logger.error("websocket", "Failed to connect", error);
190
+ throw error;
191
+ }
192
+ }
193
+ /**
194
+ * Disconnect from the WebSocket server
195
+ * Prevents automatic reconnection
196
+ */
197
+ disconnect() {
198
+ this.isManualDisconnect = true;
199
+ if (this.reconnectTimer) {
200
+ clearTimeout(this.reconnectTimer);
201
+ this.reconnectTimer = null;
202
+ }
203
+ if (this.ws) {
204
+ if (this.userId) {
205
+ this.sendMessage({
206
+ event: "pusher:unsubscribe",
207
+ data: {
208
+ channel: `private-user.${this.userId}`
209
+ }
210
+ });
211
+ }
212
+ this.ws.close();
213
+ this.ws = null;
214
+ logger.info("websocket", "WebSocket disconnected");
215
+ }
216
+ }
217
+ /**
218
+ * Check if WebSocket is currently connected
219
+ * @returns True if connected and ready
220
+ */
221
+ isConnected() {
222
+ return this.ws !== null && this.ws.readyState === WebSocket.OPEN;
223
+ }
224
+ /**
225
+ * Subscribe to user-specific channel for real-time updates
226
+ * @param userId - User ID to subscribe to
227
+ */
228
+ subscribeToUserChannel(userId) {
229
+ this.userId = userId;
230
+ if (!this.isConnected()) {
231
+ logger.warn("websocket", "Cannot subscribe: not connected");
232
+ return;
233
+ }
234
+ const channel = `private-user.${userId}`;
235
+ logger.info("websocket", `Subscribing to channel: ${channel}`);
236
+ this.sendMessage({
237
+ event: "pusher:subscribe",
238
+ data: {
239
+ channel
240
+ }
241
+ });
242
+ }
243
+ /**
244
+ * Register handler for commit approved events
245
+ * @param handler - Callback function
246
+ */
247
+ onCommitApproved(handler) {
248
+ this.commitApprovedHandlers.push(handler);
249
+ }
250
+ onCommitPending(handler) {
251
+ this.commitPendingHandlers.push(handler);
252
+ }
253
+ onSuggestionCreated(handler) {
254
+ this.suggestionCreatedHandlers.push(handler);
255
+ }
256
+ onProjectUpdated(handler) {
257
+ this.projectUpdatedHandlers.push(handler);
258
+ }
259
+ onDisconnect(handler) {
260
+ this.disconnectHandlers.push(handler);
261
+ }
262
+ onAgentDisconnected(handler) {
263
+ this.agentDisconnectedHandlers.push(handler);
264
+ }
265
+ onSyncRequested(handler) {
266
+ this.syncRequestedHandlers.push(handler);
267
+ }
268
+ sendMessage(message) {
269
+ if (!this.isConnected()) {
270
+ logger.warn("websocket", "Cannot send message: not connected");
271
+ return;
272
+ }
273
+ this.ws.send(JSON.stringify(message));
274
+ }
275
+ handleMessage(data) {
276
+ try {
277
+ const message = JSON.parse(data.toString());
278
+ logger.debug("websocket", `Received message: ${message.event}`);
279
+ if (message.event === "pusher:connection_established") {
280
+ logger.success("websocket", "Connection established");
281
+ return;
282
+ }
283
+ if (message.event === "pusher_internal:subscription_succeeded") {
284
+ logger.success("websocket", `Subscribed to channel: ${message.channel}`);
285
+ return;
286
+ }
287
+ if (message.event === "commit.approved") {
288
+ const { commit, project } = message.data;
289
+ logger.info("websocket", `Commit approved: ${commit.id}`);
290
+ this.commitApprovedHandlers.forEach((handler) => handler(commit, project));
291
+ return;
292
+ }
293
+ if (message.event === "commit.pending") {
294
+ const { pendingCommit } = message.data;
295
+ logger.info("websocket", `Commit pending: ${pendingCommit.id}`);
296
+ this.commitPendingHandlers.forEach((handler) => handler(pendingCommit));
297
+ return;
298
+ }
299
+ if (message.event === "suggestion.created") {
300
+ const { suggestion } = message.data;
301
+ logger.info("websocket", `Suggestion created: ${suggestion.id}`);
302
+ this.suggestionCreatedHandlers.forEach((handler) => handler(suggestion));
303
+ return;
304
+ }
305
+ if (message.event === "project.updated") {
306
+ const { project } = message.data;
307
+ logger.info("websocket", `Project updated: ${project.id}`);
308
+ this.projectUpdatedHandlers.forEach((handler) => handler(project));
309
+ return;
310
+ }
311
+ if (message.event === "sync.requested") {
312
+ const { projectId } = message.data;
313
+ logger.info("websocket", `Sync requested for project: ${projectId}`);
314
+ this.syncRequestedHandlers.forEach((handler) => handler(projectId));
315
+ return;
316
+ }
317
+ if (message.event === "agent.disconnected") {
318
+ const reason = message.data?.reason || "Server requested disconnect";
319
+ logger.warn("websocket", `Agent disconnected by server: ${reason}`);
320
+ this.agentDisconnectedHandlers.forEach((handler) => handler(reason));
321
+ return;
322
+ }
323
+ logger.debug("websocket", `Unhandled event: ${message.event}`);
324
+ } catch (error) {
325
+ logger.error("websocket", "Failed to parse message", error);
326
+ }
327
+ }
328
+ handleDisconnect() {
329
+ this.ws = null;
330
+ this.disconnectHandlers.forEach((handler) => handler());
331
+ if (this.isManualDisconnect) {
332
+ return;
333
+ }
334
+ if (this.reconnectAttempts < this.maxReconnectAttempts) {
335
+ const delay = this.getReconnectDelay();
336
+ this.reconnectAttempts++;
337
+ logger.info("websocket", `Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts})`);
338
+ this.reconnectTimer = setTimeout(async () => {
339
+ try {
340
+ await this.connect();
341
+ if (this.userId) {
342
+ this.subscribeToUserChannel(this.userId);
343
+ }
344
+ } catch (error) {
345
+ logger.error("websocket", "Reconnection failed", error);
346
+ }
347
+ }, delay);
348
+ } else {
349
+ logger.error("websocket", "Max reconnection attempts reached");
350
+ }
351
+ }
352
+ /**
353
+ * Get reconnect delay with exponential backoff and jitter
354
+ * Jitter prevents thundering herd problem when many clients reconnect simultaneously
355
+ */
356
+ getReconnectDelay() {
357
+ const delays = [1e3, 2e3, 4e3, 8e3, 16e3, 3e4];
358
+ const index = Math.min(this.reconnectAttempts, delays.length - 1);
359
+ const baseDelay = delays[index];
360
+ const jitter = baseDelay * (Math.random() * 0.3);
361
+ return Math.floor(baseDelay + jitter);
362
+ }
363
+ };
364
+ var websocketService = new WebSocketServiceImpl();
365
+
366
+ export {
367
+ commitQueue,
368
+ websocketService
369
+ };
@@ -0,0 +1,297 @@
1
+ // src/utils/config.ts
2
+ import Conf from "conf";
3
+ import { createHash } from "crypto";
4
+ import os from "os";
5
+ function generateStableMachineId() {
6
+ const machineInfo = [
7
+ os.hostname(),
8
+ os.userInfo().username,
9
+ os.platform(),
10
+ os.arch()
11
+ ].join("-");
12
+ const hash = createHash("sha256").update(machineInfo).digest("hex");
13
+ return `${hash.slice(0, 8)}-${hash.slice(8, 12)}-${hash.slice(12, 16)}-${hash.slice(16, 20)}-${hash.slice(20, 32)}`;
14
+ }
15
+ var DEFAULT_CONFIG = {
16
+ apiUrl: "https://stint.codes",
17
+ wsUrl: "wss://stint.codes/reverb",
18
+ reverbAppKey: "wtn6tu6lirfv6yflujk7",
19
+ projects: {}
20
+ };
21
+ var ConfigManager = class {
22
+ conf;
23
+ constructor() {
24
+ this.conf = new Conf({
25
+ projectName: "stint",
26
+ defaults: {
27
+ ...DEFAULT_CONFIG,
28
+ machineId: generateStableMachineId(),
29
+ machineName: os.hostname()
30
+ }
31
+ });
32
+ }
33
+ get(key) {
34
+ return this.conf.get(key);
35
+ }
36
+ set(key, value) {
37
+ this.conf.set(key, value);
38
+ }
39
+ getAll() {
40
+ return this.conf.store;
41
+ }
42
+ clear() {
43
+ this.conf.clear();
44
+ }
45
+ // Token management
46
+ getToken() {
47
+ return this.conf.get("token");
48
+ }
49
+ setToken(token) {
50
+ this.conf.set("token", token);
51
+ }
52
+ clearToken() {
53
+ this.conf.delete("token");
54
+ }
55
+ // Machine info
56
+ getMachineId() {
57
+ return this.conf.get("machineId");
58
+ }
59
+ getMachineName() {
60
+ return this.conf.get("machineName");
61
+ }
62
+ // Normalize path to use forward slashes for consistent storage/lookup
63
+ normalizePath(p) {
64
+ return p.replace(/\\/g, "/");
65
+ }
66
+ // Project management
67
+ getProjects() {
68
+ return this.conf.get("projects") || {};
69
+ }
70
+ getProject(path2) {
71
+ const projects = this.getProjects();
72
+ const normalizedPath = this.normalizePath(path2);
73
+ return projects[normalizedPath];
74
+ }
75
+ setProject(path2, project) {
76
+ const projects = this.getProjects();
77
+ const normalizedPath = this.normalizePath(path2);
78
+ projects[normalizedPath] = project;
79
+ this.conf.set("projects", projects);
80
+ }
81
+ removeProject(path2) {
82
+ const projects = this.getProjects();
83
+ const normalizedPath = this.normalizePath(path2);
84
+ delete projects[normalizedPath];
85
+ this.conf.set("projects", projects);
86
+ }
87
+ // API URLs
88
+ getApiUrl() {
89
+ return this.conf.get("apiUrl");
90
+ }
91
+ getWsUrl() {
92
+ const environment = this.getEnvironment();
93
+ const reverbAppKey = this.getReverbAppKey();
94
+ let baseUrl;
95
+ if (environment === "development") {
96
+ baseUrl = "ws://localhost:8080";
97
+ } else {
98
+ baseUrl = this.conf.get("wsUrl") || "wss://stint.codes/reverb";
99
+ }
100
+ if (reverbAppKey && reverbAppKey.trim() !== "") {
101
+ const cleanBaseUrl2 = baseUrl.replace(/\/$/, "");
102
+ const baseWithoutReverb = cleanBaseUrl2.replace(/\/reverb$/, "");
103
+ return `${baseWithoutReverb}/app/${reverbAppKey}`;
104
+ }
105
+ const cleanBaseUrl = baseUrl.replace(/\/$/, "");
106
+ if (!cleanBaseUrl.includes("/reverb")) {
107
+ return `${cleanBaseUrl}/reverb`;
108
+ }
109
+ return cleanBaseUrl;
110
+ }
111
+ // Environment management
112
+ getEnvironment() {
113
+ const configEnv = this.conf.get("environment");
114
+ if (configEnv === "development" || configEnv === "production") {
115
+ return configEnv;
116
+ }
117
+ const nodeEnv = process.env.NODE_ENV;
118
+ if (nodeEnv === "development" || nodeEnv === "dev") {
119
+ return "development";
120
+ }
121
+ return "production";
122
+ }
123
+ setEnvironment(environment) {
124
+ this.conf.set("environment", environment);
125
+ }
126
+ // Reverb App Key management
127
+ getReverbAppKey() {
128
+ return process.env.REVERB_APP_KEY || process.env.STINT_REVERB_APP_KEY || this.conf.get("reverbAppKey");
129
+ }
130
+ setReverbAppKey(reverbAppKey) {
131
+ this.conf.set("reverbAppKey", reverbAppKey);
132
+ }
133
+ };
134
+ var config = new ConfigManager();
135
+
136
+ // src/utils/logger.ts
137
+ import fs from "fs";
138
+ import path from "path";
139
+ import os2 from "os";
140
+ var LOG_DIR = path.join(os2.homedir(), ".config", "stint", "logs");
141
+ var AGENT_LOG = path.join(LOG_DIR, "agent.log");
142
+ var ERROR_LOG = path.join(LOG_DIR, "error.log");
143
+ var MAX_LOG_SIZE = 10 * 1024 * 1024;
144
+ var MAX_LOG_FILES = 7;
145
+ var Logger = class {
146
+ ensureLogDir() {
147
+ if (!fs.existsSync(LOG_DIR)) {
148
+ fs.mkdirSync(LOG_DIR, { recursive: true });
149
+ }
150
+ }
151
+ rotateLog(logFile) {
152
+ if (!fs.existsSync(logFile)) return;
153
+ const stats = fs.statSync(logFile);
154
+ if (stats.size < MAX_LOG_SIZE) return;
155
+ for (let i = MAX_LOG_FILES - 1; i > 0; i--) {
156
+ const oldFile = `${logFile}.${i}`;
157
+ const newFile = `${logFile}.${i + 1}`;
158
+ if (fs.existsSync(oldFile)) {
159
+ if (i === MAX_LOG_FILES - 1) {
160
+ fs.unlinkSync(oldFile);
161
+ } else {
162
+ fs.renameSync(oldFile, newFile);
163
+ }
164
+ }
165
+ }
166
+ fs.renameSync(logFile, `${logFile}.1`);
167
+ }
168
+ writeLog(level, category, message, logFile) {
169
+ this.ensureLogDir();
170
+ this.rotateLog(logFile);
171
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
172
+ const logLine = `[${timestamp}] ${level.padEnd(5)} [${category}] ${message}
173
+ `;
174
+ fs.appendFileSync(logFile, logLine);
175
+ }
176
+ info(category, message) {
177
+ this.writeLog("INFO", category, message, AGENT_LOG);
178
+ console.log(`\u2139 [${category}] ${message}`);
179
+ }
180
+ warn(category, message) {
181
+ this.writeLog("WARN", category, message, AGENT_LOG);
182
+ console.warn(`\u26A0 [${category}] ${message}`);
183
+ }
184
+ error(category, message, error) {
185
+ const fullMessage = error ? `${message}: ${error.message}` : message;
186
+ this.writeLog("ERROR", category, fullMessage, ERROR_LOG);
187
+ this.writeLog("ERROR", category, fullMessage, AGENT_LOG);
188
+ console.error(`\u2716 [${category}] ${fullMessage}`);
189
+ if (error?.stack) {
190
+ this.writeLog("ERROR", category, error.stack, ERROR_LOG);
191
+ }
192
+ }
193
+ debug(category, message) {
194
+ if (process.env.DEBUG) {
195
+ this.writeLog("DEBUG", category, message, AGENT_LOG);
196
+ console.debug(`\u{1F41B} [${category}] ${message}`);
197
+ }
198
+ }
199
+ success(category, message) {
200
+ this.writeLog("INFO", category, message, AGENT_LOG);
201
+ console.log(`\u2713 [${category}] ${message}`);
202
+ }
203
+ };
204
+ var logger = new Logger();
205
+
206
+ // src/utils/crypto.ts
207
+ import crypto from "crypto";
208
+ import os3 from "os";
209
+ function getMachineKey() {
210
+ const machineInfo = `${os3.hostname()}-${os3.platform()}-${os3.arch()}`;
211
+ return crypto.createHash("sha256").update(machineInfo).digest();
212
+ }
213
+ var ALGORITHM = "aes-256-gcm";
214
+ var IV_LENGTH = 16;
215
+ var AUTH_TAG_LENGTH = 16;
216
+ function encrypt(text) {
217
+ const key = getMachineKey();
218
+ const iv = crypto.randomBytes(IV_LENGTH);
219
+ const cipher = crypto.createCipheriv(ALGORITHM, key, iv);
220
+ let encrypted = cipher.update(text, "utf8", "hex");
221
+ encrypted += cipher.final("hex");
222
+ const authTag = cipher.getAuthTag();
223
+ return iv.toString("hex") + authTag.toString("hex") + encrypted;
224
+ }
225
+ function decrypt(encryptedText) {
226
+ const key = getMachineKey();
227
+ const iv = Buffer.from(encryptedText.slice(0, IV_LENGTH * 2), "hex");
228
+ const authTag = Buffer.from(
229
+ encryptedText.slice(IV_LENGTH * 2, (IV_LENGTH + AUTH_TAG_LENGTH) * 2),
230
+ "hex"
231
+ );
232
+ const encrypted = encryptedText.slice((IV_LENGTH + AUTH_TAG_LENGTH) * 2);
233
+ const decipher = crypto.createDecipheriv(ALGORITHM, key, iv);
234
+ decipher.setAuthTag(authTag);
235
+ let decrypted = decipher.update(encrypted, "hex", "utf8");
236
+ decrypted += decipher.final("utf8");
237
+ return decrypted;
238
+ }
239
+
240
+ // src/services/auth.ts
241
+ var AuthServiceImpl = class {
242
+ async saveToken(token) {
243
+ try {
244
+ const encryptedToken = encrypt(token);
245
+ config.setToken(encryptedToken);
246
+ logger.info("auth", "Token saved successfully");
247
+ } catch (error) {
248
+ logger.error("auth", "Failed to save token", error);
249
+ throw error;
250
+ }
251
+ }
252
+ async getToken() {
253
+ try {
254
+ const encryptedToken = config.getToken();
255
+ if (!encryptedToken) {
256
+ return null;
257
+ }
258
+ return decrypt(encryptedToken);
259
+ } catch (error) {
260
+ logger.error("auth", "Failed to decrypt token", error);
261
+ return null;
262
+ }
263
+ }
264
+ async clearToken() {
265
+ config.clearToken();
266
+ logger.info("auth", "Token cleared");
267
+ }
268
+ async validateToken() {
269
+ const token = await this.getToken();
270
+ if (!token) {
271
+ return null;
272
+ }
273
+ try {
274
+ const { apiService } = await import("./api-HLTR2LTF.js");
275
+ const user = await apiService.getCurrentUser();
276
+ logger.info("auth", `Token validated for user: ${user.email}`);
277
+ return user;
278
+ } catch (error) {
279
+ logger.warn("auth", "Token validation failed");
280
+ logger.error("auth", "Failed to validate token", error);
281
+ return null;
282
+ }
283
+ }
284
+ getMachineId() {
285
+ return config.getMachineId();
286
+ }
287
+ getMachineName() {
288
+ return config.getMachineName();
289
+ }
290
+ };
291
+ var authService = new AuthServiceImpl();
292
+
293
+ export {
294
+ config,
295
+ logger,
296
+ authService
297
+ };