@gowelle/stint-agent 1.0.2 → 1.0.3

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 CHANGED
@@ -34,7 +34,7 @@ stint login
34
34
  # Check your authentication status
35
35
  stint whoami
36
36
 
37
- # Link a project
37
+ # Link a project (or create a new one)
38
38
  cd /path/to/your/project
39
39
  stint link
40
40
 
@@ -47,6 +47,13 @@ stint daemon status
47
47
 
48
48
  ## Commands
49
49
 
50
+ ### General
51
+
52
+ | Command | Description |
53
+ |---------|-------------|
54
+ | `stint --version`, `stint -V` | Show current agent version |
55
+ | `stint --help`, `stint -h` | Show help information |
56
+
50
57
  ### Authentication
51
58
 
52
59
  | Command | Description |
@@ -69,7 +76,7 @@ stint daemon status
69
76
 
70
77
  | Command | Description |
71
78
  |---------|-------------|
72
- | `stint link` | Link current directory to a Stint project |
79
+ | `stint link` | Link current directory to a Stint project (or create a new one) |
73
80
  | `stint unlink [--force]` | Remove project link |
74
81
  | `stint status` | Show project, git, auth, and daemon status |
75
82
  | `stint sync` | Manually sync repository information to server |
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  apiService
3
- } from "./chunk-5XNQJJVE.js";
3
+ } from "./chunk-NMOUYAW2.js";
4
4
  export {
5
5
  apiService
6
6
  };
@@ -2,7 +2,7 @@ import {
2
2
  apiService,
3
3
  config,
4
4
  logger
5
- } from "./chunk-5XNQJJVE.js";
5
+ } from "./chunk-NMOUYAW2.js";
6
6
 
7
7
  // src/utils/process.ts
8
8
  import fs from "fs";
@@ -254,7 +254,7 @@ var AuthServiceImpl = class {
254
254
  return null;
255
255
  }
256
256
  try {
257
- const { apiService: apiService2 } = await import("./api-ZMYJOXXU.js");
257
+ const { apiService: apiService2 } = await import("./api-37DCZYLF.js");
258
258
  const user = await apiService2.getCurrentUser();
259
259
  logger.info("auth", `Token validated for user: ${user.email}`);
260
260
  return user;
@@ -274,7 +274,7 @@ var AuthServiceImpl = class {
274
274
  var authService = new AuthServiceImpl();
275
275
 
276
276
  // src/services/api.ts
277
- var AGENT_VERSION = "1.0.2";
277
+ var AGENT_VERSION = "1.0.3";
278
278
  var ApiServiceImpl = class {
279
279
  sessionId = null;
280
280
  async getHeaders() {
@@ -351,7 +351,7 @@ var ApiServiceImpl = class {
351
351
  return session;
352
352
  }, "Connect");
353
353
  }
354
- async disconnect() {
354
+ async disconnect(reason) {
355
355
  if (!this.sessionId) {
356
356
  return;
357
357
  }
@@ -359,7 +359,8 @@ var ApiServiceImpl = class {
359
359
  await this.request("/api/agent/disconnect", {
360
360
  method: "POST",
361
361
  body: JSON.stringify({
362
- session_id: this.sessionId
362
+ session_id: this.sessionId,
363
+ reason: reason || "Agent disconnected"
363
364
  })
364
365
  });
365
366
  this.sessionId = null;
@@ -5,13 +5,13 @@ import {
5
5
  projectService,
6
6
  removePidFile,
7
7
  writePidFile
8
- } from "../chunk-WFWZCAJ6.js";
8
+ } from "../chunk-EVWSJ3RU.js";
9
9
  import {
10
10
  apiService,
11
11
  authService,
12
12
  config,
13
13
  logger
14
- } from "../chunk-5XNQJJVE.js";
14
+ } from "../chunk-NMOUYAW2.js";
15
15
 
16
16
  // src/daemon/runner.ts
17
17
  import "dotenv/config";
@@ -27,8 +27,12 @@ var WebSocketServiceImpl = class {
27
27
  isManualDisconnect = false;
28
28
  // Event handlers
29
29
  commitApprovedHandlers = [];
30
+ commitPendingHandlers = [];
31
+ suggestionCreatedHandlers = [];
30
32
  projectUpdatedHandlers = [];
31
33
  disconnectHandlers = [];
34
+ agentDisconnectedHandlers = [];
35
+ syncRequestedHandlers = [];
32
36
  async connect() {
33
37
  try {
34
38
  const token = await authService.getToken();
@@ -108,12 +112,24 @@ var WebSocketServiceImpl = class {
108
112
  onCommitApproved(handler) {
109
113
  this.commitApprovedHandlers.push(handler);
110
114
  }
115
+ onCommitPending(handler) {
116
+ this.commitPendingHandlers.push(handler);
117
+ }
118
+ onSuggestionCreated(handler) {
119
+ this.suggestionCreatedHandlers.push(handler);
120
+ }
111
121
  onProjectUpdated(handler) {
112
122
  this.projectUpdatedHandlers.push(handler);
113
123
  }
114
124
  onDisconnect(handler) {
115
125
  this.disconnectHandlers.push(handler);
116
126
  }
127
+ onAgentDisconnected(handler) {
128
+ this.agentDisconnectedHandlers.push(handler);
129
+ }
130
+ onSyncRequested(handler) {
131
+ this.syncRequestedHandlers.push(handler);
132
+ }
117
133
  sendMessage(message) {
118
134
  if (!this.isConnected()) {
119
135
  logger.warn("websocket", "Cannot send message: not connected");
@@ -139,6 +155,18 @@ var WebSocketServiceImpl = class {
139
155
  this.commitApprovedHandlers.forEach((handler) => handler(commit, project));
140
156
  return;
141
157
  }
158
+ if (message.event === "commit.pending") {
159
+ const { pendingCommit } = message.data;
160
+ logger.info("websocket", `Commit pending: ${pendingCommit.id}`);
161
+ this.commitPendingHandlers.forEach((handler) => handler(pendingCommit));
162
+ return;
163
+ }
164
+ if (message.event === "suggestion.created") {
165
+ const { suggestion } = message.data;
166
+ logger.info("websocket", `Suggestion created: ${suggestion.id}`);
167
+ this.suggestionCreatedHandlers.forEach((handler) => handler(suggestion));
168
+ return;
169
+ }
142
170
  if (message.event === "project.updated") {
143
171
  const { project } = message.data;
144
172
  logger.info("websocket", `Project updated: ${project.id}`);
@@ -148,6 +176,13 @@ var WebSocketServiceImpl = class {
148
176
  if (message.event === "sync.requested") {
149
177
  const { projectId } = message.data;
150
178
  logger.info("websocket", `Sync requested for project: ${projectId}`);
179
+ this.syncRequestedHandlers.forEach((handler) => handler(projectId));
180
+ return;
181
+ }
182
+ if (message.event === "agent.disconnected") {
183
+ const reason = message.data?.reason || "Server requested disconnect";
184
+ logger.warn("websocket", `Agent disconnected by server: ${reason}`);
185
+ this.agentDisconnectedHandlers.forEach((handler) => handler(reason));
151
186
  return;
152
187
  }
153
188
  logger.debug("websocket", `Unhandled event: ${message.event}`);
@@ -358,6 +393,19 @@ var FileWatcher = class {
358
393
  addProject(projectPath, projectId) {
359
394
  this.watchProject(projectPath, projectId);
360
395
  }
396
+ /**
397
+ * Sync a project by ID (called when server requests a sync)
398
+ */
399
+ async syncProjectById(projectId) {
400
+ const linkedProjects = projectService.getAllLinkedProjects();
401
+ for (const [projectPath, linkedProject] of Object.entries(linkedProjects)) {
402
+ if (linkedProject.projectId === projectId) {
403
+ await this.performSync(projectPath, projectId);
404
+ return;
405
+ }
406
+ }
407
+ logger.warn("watcher", `Cannot sync: project ${projectId} not found in linked projects`);
408
+ }
361
409
  /**
362
410
  * Remove a project from watching (called when a project is unlinked)
363
411
  */
@@ -377,9 +425,32 @@ var FileWatcher = class {
377
425
  }
378
426
  };
379
427
 
428
+ // src/utils/notify.ts
429
+ import notifier from "node-notifier";
430
+ function notify(options) {
431
+ try {
432
+ notifier.notify({
433
+ title: options.title,
434
+ message: options.message,
435
+ open: options.open,
436
+ sound: true,
437
+ wait: false,
438
+ appID: "Stint Agent"
439
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
440
+ }, (error) => {
441
+ if (error) {
442
+ logger.error("notify", "Failed to send notification", error);
443
+ }
444
+ });
445
+ } catch (error) {
446
+ logger.error("notify", "Failed to send notification", error);
447
+ }
448
+ }
449
+
380
450
  // src/daemon/index.ts
381
451
  var heartbeatInterval = null;
382
452
  var isShuttingDown = false;
453
+ var shutdownReason;
383
454
  var fileWatcher = new FileWatcher();
384
455
  async function startDaemon() {
385
456
  logger.info("daemon", "Starting daemon...");
@@ -406,6 +477,30 @@ async function startDaemon() {
406
477
  websocketService.onDisconnect(() => {
407
478
  logger.warn("daemon", "WebSocket disconnected, will attempt to reconnect");
408
479
  });
480
+ websocketService.onAgentDisconnected(async (reason) => {
481
+ logger.warn("daemon", `Server disconnected agent: ${reason}`);
482
+ logger.info("daemon", "Initiating graceful shutdown...");
483
+ await shutdown(`Server: ${reason}`);
484
+ process.exit(0);
485
+ });
486
+ websocketService.onSuggestionCreated((suggestion) => {
487
+ logger.info("daemon", `Suggestion created: ${suggestion.title} (${suggestion.priority})`);
488
+ notify({
489
+ title: "New Suggestion",
490
+ message: `${suggestion.title}
491
+ Priority: ${suggestion.priority}`,
492
+ open: `https://stint.codes/projects/${suggestion.project_id}/suggestions/${suggestion.id}`
493
+ // Hypothetical URL structure
494
+ });
495
+ });
496
+ websocketService.onSyncRequested(async (projectId) => {
497
+ logger.info("daemon", `Server requested sync for project: ${projectId}`);
498
+ try {
499
+ await fileWatcher.syncProjectById(projectId);
500
+ } catch (error) {
501
+ logger.error("daemon", `Failed to sync project ${projectId}`, error);
502
+ }
503
+ });
409
504
  setupSignalHandlers();
410
505
  startHeartbeat();
411
506
  fileWatcher.start();
@@ -443,15 +538,16 @@ function setupSignalHandlers() {
443
538
  signals.forEach((signal) => {
444
539
  process.on(signal, async () => {
445
540
  logger.info("daemon", `Received ${signal}, shutting down...`);
446
- await shutdown();
541
+ await shutdown(`Signal: ${signal}`);
447
542
  process.exit(0);
448
543
  });
449
544
  });
450
545
  logger.info("daemon", "Signal handlers registered");
451
546
  }
452
- async function shutdown() {
547
+ async function shutdown(reason) {
453
548
  if (isShuttingDown) return;
454
549
  isShuttingDown = true;
550
+ shutdownReason = reason;
455
551
  logger.info("daemon", "Shutting down daemon...");
456
552
  stopHeartbeat();
457
553
  try {
@@ -467,7 +563,7 @@ async function shutdown() {
467
563
  logger.error("daemon", "Failed to disconnect from WebSocket", error);
468
564
  }
469
565
  try {
470
- await apiService.disconnect();
566
+ await apiService.disconnect(shutdownReason);
471
567
  logger.info("daemon", "Disconnected from API");
472
568
  } catch (error) {
473
569
  logger.error("daemon", "Failed to disconnect from API", error);
package/dist/index.js CHANGED
@@ -8,13 +8,13 @@ import {
8
8
  projectService,
9
9
  spawnDetached,
10
10
  validatePidFile
11
- } from "./chunk-WFWZCAJ6.js";
11
+ } from "./chunk-EVWSJ3RU.js";
12
12
  import {
13
13
  apiService,
14
14
  authService,
15
15
  config,
16
16
  logger
17
- } from "./chunk-5XNQJJVE.js";
17
+ } from "./chunk-NMOUYAW2.js";
18
18
 
19
19
  // src/index.ts
20
20
  import "dotenv/config";
@@ -514,7 +514,7 @@ function registerLinkCommand(program2) {
514
514
  try {
515
515
  repoInfo = await gitService.getRepoInfo(cwd);
516
516
  } catch (e) {
517
- logger.warn("link", "Failed to get repo info for creation metadata", e);
517
+ logger.warn("link", `Failed to get repo info for creation metadata: ${e.message}`);
518
518
  }
519
519
  }
520
520
  const newProject = await apiService.createProject({
@@ -1062,7 +1062,7 @@ function getTimeAgo(date) {
1062
1062
  }
1063
1063
 
1064
1064
  // src/index.ts
1065
- var AGENT_VERSION = "1.0.2";
1065
+ var AGENT_VERSION = "1.0.3";
1066
1066
  var program = new Command();
1067
1067
  program.name("stint").description("Stint Agent - Local daemon for Stint Project Assistant").version(AGENT_VERSION, "-V, --version", "output the current version").addHelpText("after", `
1068
1068
  ${chalk10.bold("Examples:")}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gowelle/stint-agent",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "Local agent for Stint - Project Assistant",
5
5
  "author": "Gowelle John <gowelle.john@icloud.com>",
6
6
  "license": "MIT",
@@ -42,6 +42,7 @@
42
42
  "conf": "^12.0.0",
43
43
  "dotenv": "^17.2.3",
44
44
  "node-fetch": "^3.3.2",
45
+ "node-notifier": "^10.0.1",
45
46
  "open": "^10.0.0",
46
47
  "ora": "^8.0.1",
47
48
  "simple-git": "^3.22.0",
@@ -49,6 +50,7 @@
49
50
  },
50
51
  "devDependencies": {
51
52
  "@types/node": "^20.11.0",
53
+ "@types/node-notifier": "^8.0.5",
52
54
  "@types/ws": "^8.5.10",
53
55
  "@typescript-eslint/eslint-plugin": "^8.50.0",
54
56
  "@typescript-eslint/parser": "^8.50.0",