@gowelle/stint-agent 1.2.35 → 1.2.36

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.
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  config,
3
3
  logger
4
- } from "./chunk-RC7Z6GTK.js";
4
+ } from "./chunk-E3WNZ2CK.js";
5
5
 
6
6
  // src/services/git.ts
7
7
  import simpleGit from "simple-git";
@@ -30,7 +30,11 @@ var GitServiceImpl = class {
30
30
  const git = this.getGit(path3);
31
31
  return await git.checkIsRepo();
32
32
  } catch (error) {
33
- logger.error("git", `Failed to check if ${path3} is a repo`, error);
33
+ logger.error(
34
+ "git",
35
+ `Failed to check if ${path3} is a repo`,
36
+ error
37
+ );
34
38
  return false;
35
39
  }
36
40
  }
@@ -53,7 +57,10 @@ var GitServiceImpl = class {
53
57
  onProgress?.("Determining default branch...");
54
58
  let defaultBranch = currentBranch;
55
59
  try {
56
- const result = await git.raw(["symbolic-ref", "refs/remotes/origin/HEAD"]);
60
+ const result = await git.raw([
61
+ "symbolic-ref",
62
+ "refs/remotes/origin/HEAD"
63
+ ]);
57
64
  const match = result.trim().match(/refs\/remotes\/origin\/(.+)/);
58
65
  if (match) {
59
66
  defaultBranch = match[1];
@@ -85,8 +92,14 @@ var GitServiceImpl = class {
85
92
  lastCommitDate: lastCommit.date
86
93
  };
87
94
  } catch (error) {
88
- logger.error("git", `Failed to get repo info for ${path3}`, error);
89
- throw new Error(`Failed to get repository information: ${error.message}`);
95
+ logger.error(
96
+ "git",
97
+ `Failed to get repo info for ${path3}`,
98
+ error
99
+ );
100
+ throw new Error(
101
+ `Failed to get repository information: ${error.message}`
102
+ );
90
103
  }
91
104
  }
92
105
  async stageAll(path3, onOutput) {
@@ -127,8 +140,14 @@ var GitServiceImpl = class {
127
140
  const branchSummary = await git.branch();
128
141
  return branchSummary.current;
129
142
  } catch (error) {
130
- logger.error("git", `Failed to get current branch in ${path3}`, error);
131
- throw new Error(`Failed to get current branch: ${error.message}`);
143
+ logger.error(
144
+ "git",
145
+ `Failed to get current branch in ${path3}`,
146
+ error
147
+ );
148
+ throw new Error(
149
+ `Failed to get current branch: ${error.message}`
150
+ );
132
151
  }
133
152
  }
134
153
  async getBranches(path3) {
@@ -221,11 +240,20 @@ var GitServiceImpl = class {
221
240
  });
222
241
  }
223
242
  }
224
- logger.info("git", `Found ${changedFiles.length} changed files in ${path3}`);
243
+ logger.info(
244
+ "git",
245
+ `Found ${changedFiles.length} changed files in ${path3}`
246
+ );
225
247
  return changedFiles;
226
248
  } catch (error) {
227
- logger.error("git", `Failed to get changed files in ${path3}`, error);
228
- throw new Error(`Failed to get changed files: ${error.message}`);
249
+ logger.error(
250
+ "git",
251
+ `Failed to get changed files in ${path3}`,
252
+ error
253
+ );
254
+ throw new Error(
255
+ `Failed to get changed files: ${error.message}`
256
+ );
229
257
  }
230
258
  }
231
259
  /**
@@ -279,7 +307,10 @@ var ProjectServiceImpl = class {
279
307
  linkedAt: (/* @__PURE__ */ new Date()).toISOString()
280
308
  };
281
309
  config.setProject(linkPath, linkedProject);
282
- logger.success("project", `Linked ${linkPath} must be to project ${projectId}`);
310
+ logger.success(
311
+ "project",
312
+ `Linked ${linkPath} must be to project ${projectId}`
313
+ );
283
314
  } catch (error) {
284
315
  logger.error("project", "Failed to link project", error);
285
316
  throw error;
@@ -350,7 +381,9 @@ function killProcess(pid, signal = "SIGTERM") {
350
381
  logger.info("process", `Sent ${signal} to process ${pid}`);
351
382
  } catch (error) {
352
383
  logger.error("process", `Failed to kill process ${pid}`, error);
353
- throw new Error(`Failed to kill process ${pid}: ${error.message}`);
384
+ throw new Error(
385
+ `Failed to kill process ${pid}: ${error.message}`
386
+ );
354
387
  }
355
388
  }
356
389
  function spawnDetached(command, args, options = {}) {
@@ -2,7 +2,7 @@ import {
2
2
  authService,
3
3
  config,
4
4
  logger
5
- } from "./chunk-RC7Z6GTK.js";
5
+ } from "./chunk-E3WNZ2CK.js";
6
6
 
7
7
  // src/utils/circuit-breaker.ts
8
8
  var CircuitBreaker = class {
@@ -61,7 +61,9 @@ var CircuitBreaker = class {
61
61
  this.lastFailureTime = Date.now();
62
62
  this.failureTimestamps.push(this.lastFailureTime);
63
63
  const windowStart = this.lastFailureTime - this.options.windowSize;
64
- this.failureTimestamps = this.failureTimestamps.filter((ts) => ts > windowStart);
64
+ this.failureTimestamps = this.failureTimestamps.filter(
65
+ (ts) => ts > windowStart
66
+ );
65
67
  this.failures = this.failureTimestamps.length;
66
68
  if (this.state === "HALF_OPEN") {
67
69
  this.state = "OPEN";
@@ -98,7 +100,7 @@ var CircuitBreaker = class {
98
100
  };
99
101
 
100
102
  // src/services/api.ts
101
- var AGENT_VERSION = "1.2.35";
103
+ var AGENT_VERSION = "1.2.36";
102
104
  var ApiServiceImpl = class {
103
105
  sessionId = null;
104
106
  circuitBreaker = new CircuitBreaker({
@@ -109,6 +111,16 @@ var ApiServiceImpl = class {
109
111
  windowSize: 6e4
110
112
  // 60s failure window
111
113
  });
114
+ /**
115
+ * Sync notification preferences from server to local config
116
+ */
117
+ syncNotificationPreferences(prefs) {
118
+ config.setNotificationsEnabled(prefs.enabled);
119
+ config.setNotificationCategory("commits", prefs.commits);
120
+ config.setNotificationCategory("sync", prefs.sync);
121
+ config.setNotificationCategory("suggestions", prefs.suggestions);
122
+ logger.debug("api", "Synced notification preferences from server");
123
+ }
112
124
  /**
113
125
  * Get authentication headers for API requests
114
126
  * @returns Headers object with Authorization and Content-Type
@@ -117,12 +129,14 @@ var ApiServiceImpl = class {
117
129
  async getHeaders() {
118
130
  const token = await authService.getToken();
119
131
  if (!token) {
120
- throw new Error('No authentication token found. Please run "stint login" first.');
132
+ throw new Error(
133
+ 'No authentication token found. Please run "stint login" first.'
134
+ );
121
135
  }
122
136
  return {
123
137
  Authorization: `Bearer ${token}`,
124
138
  "Content-Type": "application/json",
125
- "Accept": "application/json"
139
+ Accept: "application/json"
126
140
  };
127
141
  }
128
142
  /**
@@ -146,7 +160,9 @@ var ApiServiceImpl = class {
146
160
  });
147
161
  if (!response.ok) {
148
162
  const errorText = await response.text();
149
- throw new Error(`API request failed: ${response.status} ${errorText}`);
163
+ throw new Error(
164
+ `API request failed: ${response.status} ${errorText}`
165
+ );
150
166
  }
151
167
  return await response.json();
152
168
  } catch (error) {
@@ -175,10 +191,16 @@ var ApiServiceImpl = class {
175
191
  }
176
192
  if (attempt < maxRetries) {
177
193
  const delay = Math.min(1e3 * Math.pow(2, attempt - 1), 5e3);
178
- logger.warn("api", `${operationName} failed, retrying in ${delay}ms (attempt ${attempt}/${maxRetries})`);
194
+ logger.warn(
195
+ "api",
196
+ `${operationName} failed, retrying in ${delay}ms (attempt ${attempt}/${maxRetries})`
197
+ );
179
198
  await new Promise((resolve) => setTimeout(resolve, delay));
180
199
  } else {
181
- logger.error("api", `${operationName} failed after ${maxRetries} attempts`);
200
+ logger.error(
201
+ "api",
202
+ `${operationName} failed after ${maxRetries} attempts`
203
+ );
182
204
  }
183
205
  }
184
206
  }
@@ -204,6 +226,9 @@ var ApiServiceImpl = class {
204
226
  });
205
227
  const session = response.data;
206
228
  this.sessionId = session.id;
229
+ if (response.notification_preferences) {
230
+ this.syncNotificationPreferences(response.notification_preferences);
231
+ }
207
232
  logger.success("api", `Agent session connected: ${session.id}`);
208
233
  return session;
209
234
  }, "Connect");
@@ -236,12 +261,15 @@ var ApiServiceImpl = class {
236
261
  throw new Error("No active session");
237
262
  }
238
263
  await this.withRetry(async () => {
239
- await this.request("/api/agent/heartbeat", {
264
+ const response = await this.request("/api/agent/heartbeat", {
240
265
  method: "POST",
241
266
  body: JSON.stringify({
242
267
  session_id: this.sessionId
243
268
  })
244
269
  });
270
+ if (response.notification_preferences) {
271
+ this.syncNotificationPreferences(response.notification_preferences);
272
+ }
245
273
  logger.debug("api", "Heartbeat sent");
246
274
  }, "Heartbeat");
247
275
  }
@@ -259,7 +287,9 @@ var ApiServiceImpl = class {
259
287
  const projectId2 = item.project_id || item.projectId;
260
288
  const createdAt = item.created_at || item.createdAt;
261
289
  if (!projectId2 || !createdAt) {
262
- throw new Error(`Invalid commit data received from API: ${JSON.stringify(item)}`);
290
+ throw new Error(
291
+ `Invalid commit data received from API: ${JSON.stringify(item)}`
292
+ );
263
293
  }
264
294
  return {
265
295
  id: item.id,
@@ -279,13 +309,17 @@ var ApiServiceImpl = class {
279
309
  */
280
310
  async getCommit(commitId) {
281
311
  logger.info("api", `Fetching commit ${commitId}`);
282
- const response = await this.request(`/api/agent/commits/${commitId}`);
312
+ const response = await this.request(
313
+ `/api/agent/commits/${commitId}`
314
+ );
283
315
  const item = response.data;
284
316
  const projectId = item.project_id || item.projectId;
285
317
  const createdAt = item.created_at || item.createdAt;
286
318
  const hasLargeFiles = item.has_large_files || item.hasLargeFiles;
287
319
  if (!projectId || !createdAt) {
288
- throw new Error(`Invalid commit data received from API: ${JSON.stringify(item)}`);
320
+ throw new Error(
321
+ `Invalid commit data received from API: ${JSON.stringify(item)}`
322
+ );
289
323
  }
290
324
  return {
291
325
  id: item.id,
@@ -305,7 +339,10 @@ var ApiServiceImpl = class {
305
339
  * @returns Updated commit data
306
340
  */
307
341
  async markCommitExecuted(commitId, sha, pushed = true, pushError) {
308
- logger.info("api", `Marking commit ${commitId} as executed (SHA: ${sha}, pushed: ${pushed})`);
342
+ logger.info(
343
+ "api",
344
+ `Marking commit ${commitId} as executed (SHA: ${sha}, pushed: ${pushed})`
345
+ );
309
346
  return this.withRetry(async () => {
310
347
  const response = await this.request(
311
348
  `/api/agent/commits/${commitId}/executed`,
@@ -319,7 +356,9 @@ var ApiServiceImpl = class {
319
356
  const createdAt = data.created_at || data.createdAt;
320
357
  const executedAt = data.executed_at || data.executedAt;
321
358
  if (!projectId || !createdAt) {
322
- throw new Error(`Invalid commit data received from API: ${JSON.stringify(data)}`);
359
+ throw new Error(
360
+ `Invalid commit data received from API: ${JSON.stringify(data)}`
361
+ );
323
362
  }
324
363
  const commit = {
325
364
  id: data.id,
@@ -373,7 +412,10 @@ var ApiServiceImpl = class {
373
412
  method: "POST",
374
413
  body: JSON.stringify(payload)
375
414
  });
376
- logger.success("api", `Project ${projectId} synced (${changedFiles?.length ?? 0} changed files)`);
415
+ logger.success(
416
+ "api",
417
+ `Project ${projectId} synced (${changedFiles?.length ?? 0} changed files)`
418
+ );
377
419
  return {
378
420
  auto_sync: response.auto_sync
379
421
  };
@@ -391,7 +433,9 @@ var ApiServiceImpl = class {
391
433
  }
392
434
  async getLinkedProjects() {
393
435
  logger.info("api", "Fetching linked projects");
394
- const response = await this.request("/api/agent/projects");
436
+ const response = await this.request(
437
+ "/api/agent/projects"
438
+ );
395
439
  const projects = response.data;
396
440
  logger.info("api", `Found ${projects.length} linked projects`);
397
441
  return projects;
@@ -407,10 +451,13 @@ var ApiServiceImpl = class {
407
451
  */
408
452
  async createProject(data) {
409
453
  logger.info("api", `Creating project: ${data.name}`);
410
- const response = await this.request("/api/agent/projects", {
411
- method: "POST",
412
- body: JSON.stringify(data)
413
- });
454
+ const response = await this.request(
455
+ "/api/agent/projects",
456
+ {
457
+ method: "POST",
458
+ body: JSON.stringify(data)
459
+ }
460
+ );
414
461
  const project = response.data;
415
462
  logger.success("api", `Created project: ${project.name} (${project.id})`);
416
463
  return project;
@@ -3,20 +3,20 @@ import {
3
3
  commitQueue,
4
4
  notify,
5
5
  websocketService
6
- } from "../chunk-MISINEGG.js";
6
+ } from "../chunk-BYBGWAQO.js";
7
7
  import {
8
8
  apiService
9
- } from "../chunk-H5GHDNXY.js";
9
+ } from "../chunk-VE7Z43P7.js";
10
10
  import {
11
11
  gitService,
12
12
  projectService,
13
13
  removePidFile,
14
14
  writePidFile
15
- } from "../chunk-4655SBXG.js";
15
+ } from "../chunk-KHLFCZRY.js";
16
16
  import {
17
17
  authService,
18
18
  logger
19
- } from "../chunk-RC7Z6GTK.js";
19
+ } from "../chunk-E3WNZ2CK.js";
20
20
 
21
21
  // src/daemon/runner.ts
22
22
  import "dotenv/config";
@@ -69,20 +69,30 @@ var FileWatcher = class {
69
69
  logger.warn("watcher", `Project path does not exist: ${projectPath}`);
70
70
  return;
71
71
  }
72
- const watcher = fs.watch(projectPath, { recursive: true }, (eventType, filename) => {
73
- if (!filename) return;
74
- const filenameStr = Buffer.isBuffer(filename) ? filename.toString("utf8") : filename;
75
- if (this.shouldIgnore(filenameStr)) {
76
- return;
77
- }
78
- logger.debug("watcher", `File change detected: ${filenameStr} (${eventType}) in ${projectPath}`);
79
- const watcherInfo = this.watchers.get(projectPath);
80
- if (watcherInfo && !watcherInfo.enabled) {
81
- logger.debug("watcher", `Auto-sync disabled for project ${projectId}, skipping sync`);
82
- return;
72
+ const watcher = fs.watch(
73
+ projectPath,
74
+ { recursive: true },
75
+ (eventType, filename) => {
76
+ if (!filename) return;
77
+ const filenameStr = Buffer.isBuffer(filename) ? filename.toString("utf8") : filename;
78
+ if (this.shouldIgnore(filenameStr)) {
79
+ return;
80
+ }
81
+ logger.debug(
82
+ "watcher",
83
+ `File change detected: ${filenameStr} (${eventType}) in ${projectPath}`
84
+ );
85
+ const watcherInfo = this.watchers.get(projectPath);
86
+ if (watcherInfo && !watcherInfo.enabled) {
87
+ logger.debug(
88
+ "watcher",
89
+ `Auto-sync disabled for project ${projectId}, skipping sync`
90
+ );
91
+ return;
92
+ }
93
+ this.debounceSync(projectPath, projectId);
83
94
  }
84
- this.debounceSync(projectPath, projectId);
85
- });
95
+ );
86
96
  watcher.on("error", (error) => {
87
97
  logger.error("watcher", `Watcher error for ${projectPath}`, error);
88
98
  const watcherInfo = this.watchers.get(projectPath);
@@ -101,7 +111,10 @@ var FileWatcher = class {
101
111
  enabled: true
102
112
  // Enabled by default until settings are fetched
103
113
  });
104
- logger.info("watcher", `Started watching: ${projectPath} (project: ${projectId})`);
114
+ logger.info(
115
+ "watcher",
116
+ `Started watching: ${projectPath} (project: ${projectId})`
117
+ );
105
118
  } catch (error) {
106
119
  logger.error("watcher", `Failed to watch ${projectPath}`, error);
107
120
  }
@@ -151,7 +164,11 @@ var FileWatcher = class {
151
164
  try {
152
165
  await this.performSync(projectPath, projectId);
153
166
  } catch (error) {
154
- logger.error("watcher", `Sync failed for ${projectPath}`, error);
167
+ logger.error(
168
+ "watcher",
169
+ `Sync failed for ${projectPath}`,
170
+ error
171
+ );
155
172
  } finally {
156
173
  watcherInfo.debounceTimer = null;
157
174
  }
@@ -165,29 +182,29 @@ var FileWatcher = class {
165
182
  try {
166
183
  const isRepo = await gitService.isRepo(projectPath);
167
184
  if (!isRepo) {
168
- logger.warn("watcher", `Project ${projectPath} is no longer a git repository`);
185
+ logger.warn(
186
+ "watcher",
187
+ `Project ${projectPath} is no longer a git repository`
188
+ );
169
189
  return;
170
190
  }
171
191
  const repoInfo = await gitService.getRepoInfo(projectPath);
172
192
  const changedFiles = await gitService.getChangedFiles(projectPath);
173
- const response = await apiService.syncProject(projectId, repoInfo, changedFiles);
193
+ const response = await apiService.syncProject(
194
+ projectId,
195
+ repoInfo,
196
+ changedFiles
197
+ );
174
198
  if (response.auto_sync) {
175
199
  this.updateProjectSettings(projectId, response.auto_sync);
176
200
  }
177
201
  logger.success("watcher", `Synced project ${projectId}`);
178
- let projectName = projectId;
179
- try {
180
- const projects = await apiService.getLinkedProjects();
181
- const p = projects.find((proj) => proj.id === projectId);
182
- if (p) projectName = p.name;
183
- } catch (_e) {
184
- }
185
- notify({
186
- title: "Sync Complete",
187
- message: `Project "${projectName}" synced successfully.`
188
- });
189
202
  } catch (error) {
190
- logger.error("watcher", `Failed to sync project ${projectId}`, error);
203
+ logger.error(
204
+ "watcher",
205
+ `Failed to sync project ${projectId}`,
206
+ error
207
+ );
191
208
  }
192
209
  }
193
210
  /**
@@ -203,7 +220,11 @@ var FileWatcher = class {
203
220
  watcherInfo.watcher.close();
204
221
  logger.debug("watcher", `Stopped watching: ${projectPath}`);
205
222
  } catch (error) {
206
- logger.error("watcher", `Error stopping watcher for ${projectPath}`, error);
223
+ logger.error(
224
+ "watcher",
225
+ `Error stopping watcher for ${projectPath}`,
226
+ error
227
+ );
207
228
  }
208
229
  }
209
230
  this.watchers.clear();
@@ -226,7 +247,10 @@ var FileWatcher = class {
226
247
  return;
227
248
  }
228
249
  }
229
- logger.warn("watcher", `Cannot sync: project ${projectId} not found in linked projects`);
250
+ logger.warn(
251
+ "watcher",
252
+ `Cannot sync: project ${projectId} not found in linked projects`
253
+ );
230
254
  }
231
255
  /**
232
256
  * Remove a project from watching (called when a project is unlinked)
@@ -242,7 +266,11 @@ var FileWatcher = class {
242
266
  this.watchers.delete(projectPath);
243
267
  logger.info("watcher", `Stopped watching: ${projectPath}`);
244
268
  } catch (error) {
245
- logger.error("watcher", `Error removing watcher for ${projectPath}`, error);
269
+ logger.error(
270
+ "watcher",
271
+ `Error removing watcher for ${projectPath}`,
272
+ error
273
+ );
246
274
  }
247
275
  }
248
276
  /**
@@ -253,7 +281,10 @@ var FileWatcher = class {
253
281
  if (watcherInfo.projectId === projectId) {
254
282
  watcherInfo.enabled = settings.enabled;
255
283
  watcherInfo.debounceDelay = settings.interval * 1e3;
256
- logger.debug("watcher", `Updated settings for project ${projectId}: enabled=${settings.enabled}, interval=${settings.interval}s`);
284
+ logger.debug(
285
+ "watcher",
286
+ `Updated settings for project ${projectId}: enabled=${settings.enabled}, interval=${settings.interval}s`
287
+ );
257
288
  }
258
289
  }
259
290
  }
@@ -284,11 +315,15 @@ async function startDaemon() {
284
315
  logger.success("daemon", "WebSocket connected");
285
316
  await websocketService.subscribeToUserChannel(user.id);
286
317
  websocketService.onCommitApproved((commit, project) => {
287
- logger.info("daemon", `Commit approved: ${commit.id} for project ${project.name}`);
318
+ logger.info(
319
+ "daemon",
320
+ `Commit approved: ${commit.id} for project ${project.name}`
321
+ );
288
322
  notify({
289
323
  title: "Commit Approved",
290
324
  message: `${commit.message}
291
- Project: ${project.name}`
325
+ Project: ${project.name}`,
326
+ category: "commits"
292
327
  });
293
328
  commitQueue.addToQueue(commit, project);
294
329
  });
@@ -304,21 +339,29 @@ Project: ${project.name}`
304
339
  }
305
340
  notify({
306
341
  title: `New Proposal - ${projectName}`,
307
- message: commit.message
342
+ message: commit.message,
343
+ category: "commits"
308
344
  });
309
345
  });
310
346
  websocketService.onProjectUpdated((project) => {
311
347
  logger.info("daemon", `Project updated: ${project.id} - ${project.name}`);
312
348
  if (project.settings?.auto_sync) {
313
- fileWatcher.updateProjectSettings(project.id, project.settings.auto_sync);
349
+ fileWatcher.updateProjectSettings(
350
+ project.id,
351
+ project.settings.auto_sync
352
+ );
314
353
  }
315
354
  notify({
316
355
  title: "Project Updated",
317
- message: project.name
356
+ message: project.name,
357
+ category: "sync"
318
358
  });
319
359
  });
320
360
  websocketService.onDisconnect(() => {
321
- logger.warn("daemon", "WebSocket disconnected, will attempt to reconnect");
361
+ logger.warn(
362
+ "daemon",
363
+ "WebSocket disconnected, will attempt to reconnect"
364
+ );
322
365
  });
323
366
  websocketService.onAgentDisconnected(async (reason) => {
324
367
  logger.warn("daemon", `Server disconnected agent: ${reason}`);
@@ -327,13 +370,16 @@ Project: ${project.name}`
327
370
  process.exit(0);
328
371
  });
329
372
  websocketService.onSuggestionCreated((suggestion) => {
330
- logger.info("daemon", `Suggestion created: ${suggestion.title} (${suggestion.priority})`);
373
+ logger.info(
374
+ "daemon",
375
+ `Suggestion created: ${suggestion.title} (${suggestion.priority})`
376
+ );
331
377
  notify({
332
378
  title: "New Suggestion",
333
379
  message: `${suggestion.title}
334
380
  Priority: ${suggestion.priority}`,
335
- open: `https://stint.codes/projects/${suggestion.project_id}/suggestions/${suggestion.id}`
336
- // Hypothetical URL structure
381
+ open: `https://stint.codes/projects/${suggestion.project_id}/suggestions/${suggestion.id}`,
382
+ category: "suggestions"
337
383
  });
338
384
  });
339
385
  websocketService.onSyncRequested(async (projectId) => {
@@ -350,11 +396,16 @@ Priority: ${suggestion.priority}`,
350
396
  }
351
397
  notify({
352
398
  title: "Sync Requested",
353
- message: `Syncing project "${projectName}"...`
399
+ message: `Syncing project "${projectName}"...`,
400
+ category: "sync"
354
401
  });
355
402
  await fileWatcher.syncProjectById(projectId);
356
403
  } catch (error) {
357
- logger.error("daemon", `Failed to sync project ${projectId}`, error);
404
+ logger.error(
405
+ "daemon",
406
+ `Failed to sync project ${projectId}`,
407
+ error
408
+ );
358
409
  }
359
410
  });
360
411
  setupSignalHandlers();
@@ -365,12 +416,19 @@ Priority: ${suggestion.priority}`,
365
416
  const linkedProjects = projectService.getAllLinkedProjects();
366
417
  const projectEntries = Object.entries(linkedProjects);
367
418
  if (projectEntries.length > 0) {
368
- logger.info("daemon", `Syncing ${projectEntries.length} linked project(s) on startup...`);
419
+ logger.info(
420
+ "daemon",
421
+ `Syncing ${projectEntries.length} linked project(s) on startup...`
422
+ );
369
423
  for (const [, linkedProject] of projectEntries) {
370
424
  try {
371
425
  await fileWatcher.syncProjectById(linkedProject.projectId);
372
426
  } catch (error) {
373
- logger.error("daemon", `Failed to sync project ${linkedProject.projectId} on startup`, error);
427
+ logger.error(
428
+ "daemon",
429
+ `Failed to sync project ${linkedProject.projectId} on startup`,
430
+ error
431
+ );
374
432
  }
375
433
  }
376
434
  logger.success("daemon", "Initial project sync complete");
@@ -431,7 +489,11 @@ async function shutdown(reason) {
431
489
  websocketService.disconnect();
432
490
  logger.info("daemon", "Disconnected from WebSocket");
433
491
  } catch (error) {
434
- logger.error("daemon", "Failed to disconnect from WebSocket", error);
492
+ logger.error(
493
+ "daemon",
494
+ "Failed to disconnect from WebSocket",
495
+ error
496
+ );
435
497
  }
436
498
  try {
437
499
  await apiService.disconnect(shutdownReason);