@gowelle/stint-agent 1.2.6 → 1.2.7

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.
@@ -2,10 +2,11 @@ import {
2
2
  gitService,
3
3
  projectService,
4
4
  validatePidFile
5
- } from "./chunk-Y3573VCA.js";
5
+ } from "./chunk-QQP6IASS.js";
6
6
  import {
7
7
  authService
8
- } from "./chunk-BQSZTSYJ.js";
8
+ } from "./chunk-EC5CDRON.js";
9
+ import "./chunk-XHXSWLUC.js";
9
10
 
10
11
  // src/components/StatusDashboard.tsx
11
12
  import { useState, useEffect } from "react";
@@ -0,0 +1,8 @@
1
+ import {
2
+ apiService
3
+ } from "./chunk-3SUNGAQM.js";
4
+ import "./chunk-EC5CDRON.js";
5
+ import "./chunk-XHXSWLUC.js";
6
+ export {
7
+ apiService
8
+ };
@@ -1,8 +1,10 @@
1
1
  import {
2
- authService,
2
+ authService
3
+ } from "./chunk-EC5CDRON.js";
4
+ import {
3
5
  config,
4
6
  logger
5
- } from "./chunk-BQSZTSYJ.js";
7
+ } from "./chunk-XHXSWLUC.js";
6
8
 
7
9
  // src/utils/circuit-breaker.ts
8
10
  var CircuitBreaker = class {
@@ -98,7 +100,7 @@ var CircuitBreaker = class {
98
100
  };
99
101
 
100
102
  // src/services/api.ts
101
- var AGENT_VERSION = "1.2.6";
103
+ var AGENT_VERSION = "1.2.7";
102
104
  var ApiServiceImpl = class {
103
105
  sessionId = null;
104
106
  circuitBreaker = new CircuitBreaker({
@@ -1,42 +1,20 @@
1
1
  import {
2
2
  apiService
3
- } from "./chunk-WKUVY5JC.js";
3
+ } from "./chunk-3SUNGAQM.js";
4
4
  import {
5
5
  gitService,
6
6
  projectService
7
- } from "./chunk-Y3573VCA.js";
7
+ } from "./chunk-QQP6IASS.js";
8
+ import {
9
+ authService
10
+ } from "./chunk-EC5CDRON.js";
11
+ import {
12
+ notify
13
+ } from "./chunk-HUQ7VJO6.js";
8
14
  import {
9
- authService,
10
15
  config,
11
16
  logger
12
- } from "./chunk-BQSZTSYJ.js";
13
-
14
- // src/utils/notify.ts
15
- import notifier from "node-notifier";
16
- function notify(options) {
17
- if (!config.areNotificationsEnabled()) {
18
- logger.debug("notify", "Notifications disabled, skipping notification");
19
- return;
20
- }
21
- try {
22
- notifier.notify({
23
- title: options.title,
24
- message: options.message,
25
- open: options.open,
26
- icon: options.icon,
27
- sound: true,
28
- wait: false,
29
- appID: "Stint Agent"
30
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
- }, (error) => {
32
- if (error) {
33
- logger.error("notify", "Failed to send notification", error);
34
- }
35
- });
36
- } catch (error) {
37
- logger.error("notify", "Failed to send notification", error);
38
- }
39
- }
17
+ } from "./chunk-XHXSWLUC.js";
40
18
 
41
19
  // src/daemon/queue.ts
42
20
  var CommitQueueProcessor = class {
@@ -209,6 +187,7 @@ import WebSocket from "ws";
209
187
  var WebSocketServiceImpl = class {
210
188
  ws = null;
211
189
  userId = null;
190
+ socketId = null;
212
191
  reconnectAttempts = 0;
213
192
  maxReconnectAttempts = 10;
214
193
  reconnectTimer = null;
@@ -298,20 +277,44 @@ var WebSocketServiceImpl = class {
298
277
  * Subscribe to user-specific channel for real-time updates
299
278
  * @param userId - User ID to subscribe to
300
279
  */
301
- subscribeToUserChannel(userId) {
280
+ async subscribeToUserChannel(userId) {
302
281
  this.userId = userId;
303
282
  if (!this.isConnected()) {
304
283
  logger.warn("websocket", "Cannot subscribe: not connected");
305
284
  return;
306
285
  }
286
+ if (!this.socketId) {
287
+ logger.warn("websocket", "Cannot subscribe: socket_id not available yet");
288
+ return;
289
+ }
307
290
  const channel = `private-user.${userId}`;
308
291
  logger.info("websocket", `Subscribing to channel: ${channel}`);
309
- this.sendMessage({
310
- event: "pusher:subscribe",
311
- data: {
312
- channel
313
- }
292
+ try {
293
+ const auth = await this.getChannelAuth(channel, this.socketId);
294
+ this.sendMessage({
295
+ event: "pusher:subscribe",
296
+ data: {
297
+ channel,
298
+ auth
299
+ }
300
+ });
301
+ } catch (error) {
302
+ logger.error("websocket", "Failed to authenticate channel subscription", error);
303
+ }
304
+ }
305
+ /**
306
+ * Get authentication signature for private channel from Laravel backend
307
+ */
308
+ async getChannelAuth(channel, socketId) {
309
+ const { apiService: apiService2 } = await import("./api-WKNSGZ7I.js");
310
+ const response = await apiService2.request("/broadcasting/auth", {
311
+ method: "POST",
312
+ body: JSON.stringify({
313
+ socket_id: socketId,
314
+ channel_name: channel
315
+ })
314
316
  });
317
+ return response.auth;
315
318
  }
316
319
  /**
317
320
  * Register handler for commit approved events
@@ -345,18 +348,45 @@ var WebSocketServiceImpl = class {
345
348
  }
346
349
  this.ws.send(JSON.stringify(message));
347
350
  }
348
- handleMessage(data) {
351
+ async handleMessage(data) {
349
352
  try {
350
353
  const message = JSON.parse(data.toString());
351
354
  logger.info("websocket", `Received message: ${message.event}`);
352
355
  if (message.event === "pusher:connection_established") {
353
- logger.success("websocket", "Connection established");
356
+ try {
357
+ const connectionData = typeof message.data === "string" ? JSON.parse(message.data) : message.data;
358
+ this.socketId = connectionData.socket_id;
359
+ logger.success("websocket", `Connection established (socket_id: ${this.socketId})`);
360
+ } catch (error) {
361
+ logger.success("websocket", "Connection established");
362
+ }
354
363
  return;
355
364
  }
356
365
  if (message.event === "pusher_internal:subscription_succeeded") {
357
366
  logger.success("websocket", `Subscribed to channel: ${message.channel}`);
358
367
  return;
359
368
  }
369
+ if (message.event === "pusher:error") {
370
+ try {
371
+ const errorData = typeof message.data === "string" ? JSON.parse(message.data) : message.data;
372
+ const errorCode = errorData.code;
373
+ const errorMessage = errorData.message;
374
+ logger.error("websocket", `WebSocket error (${errorCode}): ${errorMessage}`);
375
+ if (errorCode === 4001) {
376
+ logger.error("websocket", "Application does not exist - check Reverb app key configuration");
377
+ } else if (errorCode === 4009) {
378
+ logger.error("websocket", "Connection is unauthorized - authentication token may be invalid or expired");
379
+ const { notify: notify2 } = await import("./notify-R6CUXTEF.js");
380
+ notify2({
381
+ title: "Stint Agent - WebSocket Error",
382
+ message: 'Connection is unauthorized. Please try restarting the daemon or running "stint login" again.'
383
+ });
384
+ }
385
+ } catch (parseError) {
386
+ logger.error("websocket", `WebSocket error: ${JSON.stringify(message.data)}`);
387
+ }
388
+ return;
389
+ }
360
390
  if (message.event === "commit.approved") {
361
391
  const { pendingCommit } = message.data;
362
392
  logger.info("websocket", `Commit approved: ${pendingCommit.id}`);
@@ -412,7 +442,7 @@ var WebSocketServiceImpl = class {
412
442
  try {
413
443
  await this.connect();
414
444
  if (this.userId) {
415
- this.subscribeToUserChannel(this.userId);
445
+ await this.subscribeToUserChannel(this.userId);
416
446
  }
417
447
  } catch (error) {
418
448
  logger.error("websocket", "Reconnection failed", error);
@@ -437,7 +467,6 @@ var WebSocketServiceImpl = class {
437
467
  var websocketService = new WebSocketServiceImpl();
438
468
 
439
469
  export {
440
- notify,
441
470
  commitQueue,
442
471
  websocketService
443
472
  };
@@ -0,0 +1,95 @@
1
+ import {
2
+ config,
3
+ logger
4
+ } from "./chunk-XHXSWLUC.js";
5
+
6
+ // src/utils/crypto.ts
7
+ import crypto from "crypto";
8
+ import os from "os";
9
+ function getMachineKey() {
10
+ const machineInfo = `${os.hostname()}-${os.platform()}-${os.arch()}`;
11
+ return crypto.createHash("sha256").update(machineInfo).digest();
12
+ }
13
+ var ALGORITHM = "aes-256-gcm";
14
+ var IV_LENGTH = 16;
15
+ var AUTH_TAG_LENGTH = 16;
16
+ function encrypt(text) {
17
+ const key = getMachineKey();
18
+ const iv = crypto.randomBytes(IV_LENGTH);
19
+ const cipher = crypto.createCipheriv(ALGORITHM, key, iv);
20
+ let encrypted = cipher.update(text, "utf8", "hex");
21
+ encrypted += cipher.final("hex");
22
+ const authTag = cipher.getAuthTag();
23
+ return iv.toString("hex") + authTag.toString("hex") + encrypted;
24
+ }
25
+ function decrypt(encryptedText) {
26
+ const key = getMachineKey();
27
+ const iv = Buffer.from(encryptedText.slice(0, IV_LENGTH * 2), "hex");
28
+ const authTag = Buffer.from(
29
+ encryptedText.slice(IV_LENGTH * 2, (IV_LENGTH + AUTH_TAG_LENGTH) * 2),
30
+ "hex"
31
+ );
32
+ const encrypted = encryptedText.slice((IV_LENGTH + AUTH_TAG_LENGTH) * 2);
33
+ const decipher = crypto.createDecipheriv(ALGORITHM, key, iv);
34
+ decipher.setAuthTag(authTag);
35
+ let decrypted = decipher.update(encrypted, "hex", "utf8");
36
+ decrypted += decipher.final("utf8");
37
+ return decrypted;
38
+ }
39
+
40
+ // src/services/auth.ts
41
+ var AuthServiceImpl = class {
42
+ async saveToken(token) {
43
+ try {
44
+ const encryptedToken = encrypt(token);
45
+ config.setToken(encryptedToken);
46
+ logger.info("auth", "Token saved successfully");
47
+ } catch (error) {
48
+ logger.error("auth", "Failed to save token", error);
49
+ throw error;
50
+ }
51
+ }
52
+ async getToken() {
53
+ try {
54
+ const encryptedToken = config.getToken();
55
+ if (!encryptedToken) {
56
+ return null;
57
+ }
58
+ return decrypt(encryptedToken);
59
+ } catch (error) {
60
+ logger.error("auth", "Failed to decrypt token", error);
61
+ return null;
62
+ }
63
+ }
64
+ async clearToken() {
65
+ config.clearToken();
66
+ logger.info("auth", "Token cleared");
67
+ }
68
+ async validateToken() {
69
+ const token = await this.getToken();
70
+ if (!token) {
71
+ return null;
72
+ }
73
+ try {
74
+ const { apiService } = await import("./api-WKNSGZ7I.js");
75
+ const user = await apiService.getCurrentUser();
76
+ logger.info("auth", `Token validated for user: ${user.email}`);
77
+ return user;
78
+ } catch (error) {
79
+ logger.warn("auth", "Token validation failed");
80
+ logger.error("auth", "Failed to validate token", error);
81
+ return null;
82
+ }
83
+ }
84
+ getMachineId() {
85
+ return config.getMachineId();
86
+ }
87
+ getMachineName() {
88
+ return config.getMachineName();
89
+ }
90
+ };
91
+ var authService = new AuthServiceImpl();
92
+
93
+ export {
94
+ authService
95
+ };
@@ -0,0 +1,35 @@
1
+ import {
2
+ config,
3
+ logger
4
+ } from "./chunk-XHXSWLUC.js";
5
+
6
+ // src/utils/notify.ts
7
+ import notifier from "node-notifier";
8
+ function notify(options) {
9
+ if (!config.areNotificationsEnabled()) {
10
+ logger.debug("notify", "Notifications disabled, skipping notification");
11
+ return;
12
+ }
13
+ try {
14
+ notifier.notify({
15
+ title: options.title,
16
+ message: options.message,
17
+ open: options.open,
18
+ icon: options.icon,
19
+ sound: true,
20
+ wait: false,
21
+ appID: "Stint Agent"
22
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
23
+ }, (error) => {
24
+ if (error) {
25
+ logger.error("notify", "Failed to send notification", error);
26
+ }
27
+ });
28
+ } catch (error) {
29
+ logger.error("notify", "Failed to send notification", error);
30
+ }
31
+ }
32
+
33
+ export {
34
+ notify
35
+ };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  config,
3
3
  logger
4
- } from "./chunk-BQSZTSYJ.js";
4
+ } from "./chunk-XHXSWLUC.js";
5
5
 
6
6
  // src/services/git.ts
7
7
  import simpleGit from "simple-git";
@@ -214,95 +214,7 @@ var Logger = class {
214
214
  };
215
215
  var logger = new Logger();
216
216
 
217
- // src/utils/crypto.ts
218
- import crypto from "crypto";
219
- import os3 from "os";
220
- function getMachineKey() {
221
- const machineInfo = `${os3.hostname()}-${os3.platform()}-${os3.arch()}`;
222
- return crypto.createHash("sha256").update(machineInfo).digest();
223
- }
224
- var ALGORITHM = "aes-256-gcm";
225
- var IV_LENGTH = 16;
226
- var AUTH_TAG_LENGTH = 16;
227
- function encrypt(text) {
228
- const key = getMachineKey();
229
- const iv = crypto.randomBytes(IV_LENGTH);
230
- const cipher = crypto.createCipheriv(ALGORITHM, key, iv);
231
- let encrypted = cipher.update(text, "utf8", "hex");
232
- encrypted += cipher.final("hex");
233
- const authTag = cipher.getAuthTag();
234
- return iv.toString("hex") + authTag.toString("hex") + encrypted;
235
- }
236
- function decrypt(encryptedText) {
237
- const key = getMachineKey();
238
- const iv = Buffer.from(encryptedText.slice(0, IV_LENGTH * 2), "hex");
239
- const authTag = Buffer.from(
240
- encryptedText.slice(IV_LENGTH * 2, (IV_LENGTH + AUTH_TAG_LENGTH) * 2),
241
- "hex"
242
- );
243
- const encrypted = encryptedText.slice((IV_LENGTH + AUTH_TAG_LENGTH) * 2);
244
- const decipher = crypto.createDecipheriv(ALGORITHM, key, iv);
245
- decipher.setAuthTag(authTag);
246
- let decrypted = decipher.update(encrypted, "hex", "utf8");
247
- decrypted += decipher.final("utf8");
248
- return decrypted;
249
- }
250
-
251
- // src/services/auth.ts
252
- var AuthServiceImpl = class {
253
- async saveToken(token) {
254
- try {
255
- const encryptedToken = encrypt(token);
256
- config.setToken(encryptedToken);
257
- logger.info("auth", "Token saved successfully");
258
- } catch (error) {
259
- logger.error("auth", "Failed to save token", error);
260
- throw error;
261
- }
262
- }
263
- async getToken() {
264
- try {
265
- const encryptedToken = config.getToken();
266
- if (!encryptedToken) {
267
- return null;
268
- }
269
- return decrypt(encryptedToken);
270
- } catch (error) {
271
- logger.error("auth", "Failed to decrypt token", error);
272
- return null;
273
- }
274
- }
275
- async clearToken() {
276
- config.clearToken();
277
- logger.info("auth", "Token cleared");
278
- }
279
- async validateToken() {
280
- const token = await this.getToken();
281
- if (!token) {
282
- return null;
283
- }
284
- try {
285
- const { apiService } = await import("./api-434J2GGQ.js");
286
- const user = await apiService.getCurrentUser();
287
- logger.info("auth", `Token validated for user: ${user.email}`);
288
- return user;
289
- } catch (error) {
290
- logger.warn("auth", "Token validation failed");
291
- logger.error("auth", "Failed to validate token", error);
292
- return null;
293
- }
294
- }
295
- getMachineId() {
296
- return config.getMachineId();
297
- }
298
- getMachineName() {
299
- return config.getMachineName();
300
- }
301
- };
302
- var authService = new AuthServiceImpl();
303
-
304
217
  export {
305
218
  config,
306
- logger,
307
- authService
219
+ logger
308
220
  };
@@ -1,22 +1,26 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  commitQueue,
4
- notify,
5
4
  websocketService
6
- } from "../chunk-E2JTYLJT.js";
5
+ } from "../chunk-4LHVG6DQ.js";
7
6
  import {
8
7
  apiService
9
- } from "../chunk-WKUVY5JC.js";
8
+ } from "../chunk-3SUNGAQM.js";
10
9
  import {
11
10
  gitService,
12
11
  projectService,
13
12
  removePidFile,
14
13
  writePidFile
15
- } from "../chunk-Y3573VCA.js";
14
+ } from "../chunk-QQP6IASS.js";
15
+ import {
16
+ authService
17
+ } from "../chunk-EC5CDRON.js";
18
+ import {
19
+ notify
20
+ } from "../chunk-HUQ7VJO6.js";
16
21
  import {
17
- authService,
18
22
  logger
19
- } from "../chunk-BQSZTSYJ.js";
23
+ } from "../chunk-XHXSWLUC.js";
20
24
 
21
25
  // src/daemon/runner.ts
22
26
  import "dotenv/config";
@@ -247,7 +251,7 @@ async function startDaemon() {
247
251
  logger.info("daemon", "Connecting to WebSocket...");
248
252
  await websocketService.connect();
249
253
  logger.success("daemon", "WebSocket connected");
250
- websocketService.subscribeToUserChannel(user.id);
254
+ await websocketService.subscribeToUserChannel(user.id);
251
255
  websocketService.onCommitApproved((commit, project) => {
252
256
  logger.info("daemon", `Commit approved: ${commit.id} for project ${project.name}`);
253
257
  notify({
package/dist/index.js CHANGED
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  commitQueue,
4
4
  websocketService
5
- } from "./chunk-E2JTYLJT.js";
5
+ } from "./chunk-4LHVG6DQ.js";
6
6
  import {
7
7
  apiService
8
- } from "./chunk-WKUVY5JC.js";
8
+ } from "./chunk-3SUNGAQM.js";
9
9
  import {
10
10
  getPidFilePath,
11
11
  gitService,
@@ -14,12 +14,15 @@ import {
14
14
  projectService,
15
15
  spawnDetached,
16
16
  validatePidFile
17
- } from "./chunk-Y3573VCA.js";
17
+ } from "./chunk-QQP6IASS.js";
18
+ import {
19
+ authService
20
+ } from "./chunk-EC5CDRON.js";
21
+ import "./chunk-HUQ7VJO6.js";
18
22
  import {
19
- authService,
20
23
  config,
21
24
  logger
22
- } from "./chunk-BQSZTSYJ.js";
25
+ } from "./chunk-XHXSWLUC.js";
23
26
 
24
27
  // src/index.ts
25
28
  import "dotenv/config";
@@ -620,7 +623,7 @@ function registerStatusCommand(program2) {
620
623
  try {
621
624
  const { render } = await import("ink");
622
625
  const { createElement } = await import("react");
623
- const { StatusDashboard } = await import("./StatusDashboard-3OZZYL62.js");
626
+ const { StatusDashboard } = await import("./StatusDashboard-R2ITRP6M.js");
624
627
  render(createElement(StatusDashboard, { cwd }));
625
628
  return;
626
629
  } catch (error) {
@@ -2000,7 +2003,7 @@ function registerDoctorCommand(program2) {
2000
2003
  }
2001
2004
 
2002
2005
  // src/index.ts
2003
- var AGENT_VERSION = "1.2.6";
2006
+ var AGENT_VERSION = "1.2.7";
2004
2007
  var program = new Command();
2005
2008
  program.name("stint").description("Stint Agent - Local daemon for Stint Project Assistant").version(AGENT_VERSION, "-v, --version", "output the current version").addHelpText("after", `
2006
2009
  ${chalk13.bold("Examples:")}
@@ -0,0 +1,7 @@
1
+ import {
2
+ notify
3
+ } from "./chunk-HUQ7VJO6.js";
4
+ import "./chunk-XHXSWLUC.js";
5
+ export {
6
+ notify
7
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gowelle/stint-agent",
3
- "version": "1.2.6",
3
+ "version": "1.2.7",
4
4
  "description": "Local agent for Stint - Project Assistant",
5
5
  "author": "Gowelle John <gowelle.john@icloud.com>",
6
6
  "license": "MIT",
@@ -1,7 +0,0 @@
1
- import {
2
- apiService
3
- } from "./chunk-WKUVY5JC.js";
4
- import "./chunk-BQSZTSYJ.js";
5
- export {
6
- apiService
7
- };