prjct-cli 1.6.5 → 1.6.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.
package/CHANGELOG.md CHANGED
@@ -1,10 +1,46 @@
1
1
  # Changelog
2
2
 
3
- ## [1.6.5] - 2026-02-07
3
+ ## [1.6.7] - 2026-02-07
4
+
5
+ ### Bug Fixes
6
+
7
+ - add context to silent catch blocks in sync-service.ts (PRJ-80) (#120)
8
+
9
+ ### Refactoring
10
+
11
+ - replace `any` types in routes-extended.ts and server.ts (PRJ-77) (#130)
12
+
13
+
14
+ ## [1.6.7] - 2026-02-07
15
+
16
+ ### Refactoring
17
+ - **Replace `any` types in routes-extended.ts and server.ts (PRJ-77)**: Added `ProjectJson`, `StateJson`, `StateTask`, `QueueJson`, `QueueTask`, `RoadmapJson` interfaces to `core/types/storage.ts`. Replaced all 33 `any` types in `core/server/routes-extended.ts` with proper typed generics. Fixed `handleConnection: (c: any)` in `core/types/server.ts` with Hono `Context` type. Disabled redundant task component in statusline default config.
18
+
19
+ ### Test Plan
20
+
21
+ #### For QA
22
+ 1. Build the project (`bun run build`) — should succeed
23
+ 2. Typecheck (`npx tsc -p core/tsconfig.json --noEmit`) — should pass clean
24
+ 3. Verify zero `any` types in `routes-extended.ts` and `server.ts`
25
+ 4. Status bar should no longer show task description segment
26
+
27
+ #### For Users
28
+ **What changed:** Internal type safety improvement. Cleaner status bar.
29
+ **Breaking changes:** None
30
+
31
+
32
+ ## [1.6.6] - 2026-02-07
4
33
 
5
34
  ### Refactoring
6
35
 
7
- - extract common agent-base.md template (PRJ-95) (#128)
36
+ - extract hardcoded values to constants (PRJ-71) (#129)
37
+
38
+
39
+ ## [1.6.8] - 2026-02-07
40
+
41
+ ### Refactor
42
+
43
+ - **Extract hardcoded values to constants (PRJ-71)**: Added `OUTPUT_LIMITS`, `STORAGE_LIMITS`, `EVENT_LIMITS` to `core/constants/index.ts`. Replaced 16 magic numbers across `output.ts` (11 truncation lengths), `bus.ts` (history limit), and `jsonl-helper.ts` (max lines, rotation size, warning threshold). All limits now configurable from one place with `as const` typing.
8
44
 
9
45
 
10
46
  ## [1.6.7] - 2026-02-07
@@ -13,7 +13,7 @@
13
13
  "position": 0
14
14
  },
15
15
  "task": {
16
- "enabled": true,
16
+ "enabled": false,
17
17
  "position": 1,
18
18
  "maxLength": 25
19
19
  },
package/core/bus/bus.ts CHANGED
@@ -9,6 +9,7 @@
9
9
 
10
10
  import fs from 'node:fs/promises'
11
11
  import path from 'node:path'
12
+ import { EVENT_LIMITS } from '../constants'
12
13
  import { getErrorMessage } from '../errors'
13
14
  import pathManager from '../infrastructure/path-manager'
14
15
  import {
@@ -45,7 +46,7 @@ class EventBus {
45
46
  this.listeners = new Map()
46
47
  this.onceListeners = new Map()
47
48
  this.history = []
48
- this.historyLimit = 100
49
+ this.historyLimit = EVENT_LIMITS.HISTORY_MAX
49
50
  this.projectId = null
50
51
  }
51
52
 
@@ -264,6 +264,65 @@ export function getTimeout(key: TimeoutKey): number {
264
264
  return TIMEOUTS[key]
265
265
  }
266
266
 
267
+ // =============================================================================
268
+ // Output Limits (PRJ-71)
269
+ // =============================================================================
270
+
271
+ /**
272
+ * Truncation lengths for CLI output messages.
273
+ * Centralizes magic numbers from output.ts.
274
+ */
275
+ export const OUTPUT_LIMITS = {
276
+ /** Spinner message truncation */
277
+ SPINNER_MSG: 45,
278
+ /** Done/success message truncation */
279
+ DONE_MSG: 50,
280
+ /** Fail message truncation */
281
+ FAIL_MSG: 65,
282
+ /** Warn message truncation */
283
+ WARN_MSG: 65,
284
+ /** Step counter message truncation */
285
+ STEP_MSG: 35,
286
+ /** Progress bar text truncation */
287
+ PROGRESS_TEXT: 25,
288
+ /** Issue title truncation in lists */
289
+ ISSUE_TITLE: 50,
290
+ /** Fallback truncation when tier config is 0 */
291
+ FALLBACK_TRUNCATE: 50,
292
+ /** Terminal clear width */
293
+ CLEAR_WIDTH: 80,
294
+ } as const
295
+
296
+ // =============================================================================
297
+ // Storage Limits (PRJ-71)
298
+ // =============================================================================
299
+
300
+ /**
301
+ * File size and line limits for JSONL/storage operations.
302
+ * Centralizes magic numbers from jsonl-helper.ts.
303
+ */
304
+ export const STORAGE_LIMITS = {
305
+ /** Default max lines for streaming JSONL reads */
306
+ JSONL_MAX_LINES: 1000,
307
+ /** File rotation threshold in MB */
308
+ ROTATION_SIZE_MB: 10,
309
+ /** Warning threshold for large files in MB */
310
+ LARGE_FILE_WARN_MB: 50,
311
+ } as const
312
+
313
+ // =============================================================================
314
+ // Event Bus Limits (PRJ-71)
315
+ // =============================================================================
316
+
317
+ /**
318
+ * Event bus configuration limits.
319
+ * Centralizes magic numbers from bus.ts.
320
+ */
321
+ export const EVENT_LIMITS = {
322
+ /** Max events kept in history */
323
+ HISTORY_MAX: 100,
324
+ } as const
325
+
267
326
  // =============================================================================
268
327
  // Combined Exports
269
328
  // =============================================================================
@@ -13,6 +13,16 @@ import { Hono } from 'hono'
13
13
  import * as jsonc from 'jsonc-parser'
14
14
  import pathManager from '../infrastructure/path-manager'
15
15
  import { isNotFoundError } from '../types/fs'
16
+ import type {
17
+ IdeasJson,
18
+ ProjectJson,
19
+ QueueJson,
20
+ QueueTask,
21
+ RoadmapJson,
22
+ ShippedJson,
23
+ StateJson,
24
+ StateTask,
25
+ } from '../types/storage'
16
26
 
17
27
  // =============================================================================
18
28
  // HELPERS
@@ -52,9 +62,9 @@ function getProjectPath(projectId: string): string {
52
62
  return path.join(PROJECTS_DIR, projectId)
53
63
  }
54
64
 
55
- async function getProjectConfig(projectId: string): Promise<any> {
65
+ async function getProjectConfig(projectId: string): Promise<ProjectJson | null> {
56
66
  const configPath = path.join(getProjectPath(projectId), 'project.json')
57
- return await readJsonFile(configPath)
67
+ return await readJsonFile<ProjectJson>(configPath)
58
68
  }
59
69
 
60
70
  async function calculateDuration(startedAt: string | undefined): Promise<string> {
@@ -97,16 +107,18 @@ export function createExtendedRoutes(): Hono {
97
107
  const config = await getProjectConfig(id)
98
108
 
99
109
  // Read state
100
- const state = await readJsonFile<any>(path.join(projectPath, 'storage/state.json'))
110
+ const state = await readJsonFile<StateJson>(path.join(projectPath, 'storage/state.json'))
101
111
 
102
112
  // Read queue for count
103
- const queue = await readJsonFile<any>(path.join(projectPath, 'storage/queue.json'))
113
+ const queue = await readJsonFile<QueueJson>(path.join(projectPath, 'storage/queue.json'))
104
114
 
105
115
  // Read ideas for count
106
- const ideas = await readJsonFile<any>(path.join(projectPath, 'storage/ideas.json'))
116
+ const ideas = await readJsonFile<IdeasJson>(path.join(projectPath, 'storage/ideas.json'))
107
117
 
108
118
  // Read shipped for count
109
- const shipped = await readJsonFile<any>(path.join(projectPath, 'storage/shipped.json'))
119
+ const shipped = await readJsonFile<ShippedJson>(
120
+ path.join(projectPath, 'storage/shipped.json')
121
+ )
110
122
 
111
123
  const currentTask = state?.currentTask
112
124
  const duration = await calculateDuration(currentTask?.startedAt)
@@ -123,8 +135,8 @@ export function createExtendedRoutes(): Hono {
123
135
  : null,
124
136
  pausedTask: state?.previousTask || null,
125
137
  stats: {
126
- queueCount: queue?.tasks?.filter((t: any) => !t.completed)?.length || 0,
127
- ideasCount: ideas?.ideas?.filter((i: any) => i.status === 'pending')?.length || 0,
138
+ queueCount: queue?.tasks?.filter((t: QueueTask) => !t.completed)?.length || 0,
139
+ ideasCount: ideas?.ideas?.filter((i) => i.status === 'pending')?.length || 0,
128
140
  shippedCount: shipped?.shipped?.length || 0,
129
141
  },
130
142
  }
@@ -154,11 +166,11 @@ export function createExtendedRoutes(): Hono {
154
166
  try {
155
167
  const [config, state, queue, ideas, shipped, roadmap] = await Promise.all([
156
168
  getProjectConfig(projectId),
157
- readJsonFile<any>(path.join(projectPath, 'storage/state.json')),
158
- readJsonFile<any>(path.join(projectPath, 'storage/queue.json')),
159
- readJsonFile<any>(path.join(projectPath, 'storage/ideas.json')),
160
- readJsonFile<any>(path.join(projectPath, 'storage/shipped.json')),
161
- readJsonFile<any>(path.join(projectPath, 'planning/roadmap.json')),
169
+ readJsonFile<StateJson>(path.join(projectPath, 'storage/state.json')),
170
+ readJsonFile<QueueJson>(path.join(projectPath, 'storage/queue.json')),
171
+ readJsonFile<IdeasJson>(path.join(projectPath, 'storage/ideas.json')),
172
+ readJsonFile<ShippedJson>(path.join(projectPath, 'storage/shipped.json')),
173
+ readJsonFile<RoadmapJson>(path.join(projectPath, 'planning/roadmap.json')),
162
174
  ])
163
175
 
164
176
  // Calculate current task duration
@@ -173,13 +185,13 @@ export function createExtendedRoutes(): Hono {
173
185
  weekStart.setDate(weekStart.getDate() - weekStart.getDay())
174
186
 
175
187
  const completedToday =
176
- queue?.tasks?.filter((t: any) => {
188
+ queue?.tasks?.filter((t: QueueTask) => {
177
189
  if (!t.completed || !t.completedAt) return false
178
190
  return new Date(t.completedAt) >= todayStart
179
191
  })?.length || 0
180
192
 
181
193
  const completedThisWeek =
182
- queue?.tasks?.filter((t: any) => {
194
+ queue?.tasks?.filter((t: QueueTask) => {
183
195
  if (!t.completed || !t.completedAt) return false
184
196
  return new Date(t.completedAt) >= weekStart
185
197
  })?.length || 0
@@ -196,8 +208,8 @@ export function createExtendedRoutes(): Hono {
196
208
  stats: {
197
209
  tasksToday: completedToday,
198
210
  tasksThisWeek: completedThisWeek,
199
- queueCount: queue?.tasks?.filter((t: any) => !t.completed)?.length || 0,
200
- ideasCount: ideas?.ideas?.filter((i: any) => i.status === 'pending')?.length || 0,
211
+ queueCount: queue?.tasks?.filter((t: QueueTask) => !t.completed)?.length || 0,
212
+ ideasCount: ideas?.ideas?.filter((i) => i.status === 'pending')?.length || 0,
201
213
  shippedCount: shipped?.shipped?.length || 0,
202
214
  },
203
215
  timestamp: new Date().toISOString(),
@@ -216,7 +228,7 @@ export function createExtendedRoutes(): Hono {
216
228
  const statePath = path.join(projectPath, 'storage/state.json')
217
229
 
218
230
  try {
219
- const state = await readJsonFile<any>(statePath)
231
+ const state = await readJsonFile<StateJson>(statePath)
220
232
 
221
233
  if (!state?.currentTask) {
222
234
  return c.json({ success: false, error: 'No active task' }, 400)
@@ -225,7 +237,7 @@ export function createExtendedRoutes(): Hono {
225
237
  const completedTask = state.currentTask
226
238
 
227
239
  // Update state
228
- const newState = {
240
+ const newState: StateJson = {
229
241
  currentTask: null,
230
242
  previousTask: null,
231
243
  lastUpdated: new Date().toISOString(),
@@ -255,13 +267,13 @@ export function createExtendedRoutes(): Hono {
255
267
  const body = await c.req.json().catch(() => ({}))
256
268
  const reason = body.reason
257
269
 
258
- const state = await readJsonFile<any>(statePath)
270
+ const state = await readJsonFile<StateJson>(statePath)
259
271
 
260
272
  if (!state?.currentTask) {
261
273
  return c.json({ success: false, error: 'No active task' }, 400)
262
274
  }
263
275
 
264
- const pausedTask = {
276
+ const pausedTask: StateTask = {
265
277
  id: state.currentTask.id,
266
278
  description: state.currentTask.description,
267
279
  status: 'paused',
@@ -270,7 +282,7 @@ export function createExtendedRoutes(): Hono {
270
282
  pauseReason: reason,
271
283
  }
272
284
 
273
- const newState = {
285
+ const newState: StateJson = {
274
286
  currentTask: null,
275
287
  previousTask: pausedTask,
276
288
  lastUpdated: new Date().toISOString(),
@@ -297,20 +309,21 @@ export function createExtendedRoutes(): Hono {
297
309
  const statePath = path.join(projectPath, 'storage/state.json')
298
310
 
299
311
  try {
300
- const state = await readJsonFile<any>(statePath)
312
+ const state = await readJsonFile<StateJson>(statePath)
301
313
 
302
314
  if (!state?.previousTask) {
303
315
  return c.json({ success: false, error: 'No paused task' }, 400)
304
316
  }
305
317
 
306
- const resumedTask = {
318
+ const resumedTask: StateTask = {
307
319
  id: state.previousTask.id,
308
320
  description: state.previousTask.description,
321
+ status: 'active',
309
322
  startedAt: new Date().toISOString(),
310
323
  sessionId: `sess_${Date.now().toString(36)}`,
311
324
  }
312
325
 
313
- const newState = {
326
+ const newState: StateJson = {
314
327
  currentTask: resumedTask,
315
328
  previousTask: null,
316
329
  lastUpdated: new Date().toISOString(),
@@ -345,8 +358,8 @@ export function createExtendedRoutes(): Hono {
345
358
  return c.json({ success: false, error: 'taskId required' }, 400)
346
359
  }
347
360
 
348
- const state = await readJsonFile<any>(statePath)
349
- const queue = await readJsonFile<any>(queuePath)
361
+ const state = await readJsonFile<StateJson>(statePath)
362
+ const queue = await readJsonFile<QueueJson>(queuePath)
350
363
 
351
364
  // Check if there's already an active task
352
365
  if (state?.currentTask) {
@@ -354,22 +367,23 @@ export function createExtendedRoutes(): Hono {
354
367
  }
355
368
 
356
369
  // Find task in queue
357
- const task = queue?.tasks?.find((t: any) => t.id === taskId)
370
+ const task = queue?.tasks?.find((t: QueueTask) => t.id === taskId)
358
371
  if (!task) {
359
372
  return c.json({ success: false, error: 'Task not found in queue' }, 404)
360
373
  }
361
374
 
362
375
  // Create new current task
363
- const newTask = {
376
+ const newTask: StateTask = {
364
377
  id: task.id,
365
378
  description: task.description,
379
+ status: 'active',
366
380
  startedAt: new Date().toISOString(),
367
381
  sessionId: `sess_${Date.now().toString(36)}`,
368
382
  featureId: task.featureId,
369
383
  }
370
384
 
371
385
  // Update state
372
- const newState = {
386
+ const newState: StateJson = {
373
387
  currentTask: newTask,
374
388
  previousTask: null,
375
389
  lastUpdated: new Date().toISOString(),
@@ -403,14 +417,17 @@ export function createExtendedRoutes(): Hono {
403
417
  return c.json({ success: false, error: 'text required' }, 400)
404
418
  }
405
419
 
406
- const ideas = (await readJsonFile<any>(ideasPath)) || { ideas: [], lastUpdated: '' }
420
+ const ideas: IdeasJson = (await readJsonFile<IdeasJson>(ideasPath)) || {
421
+ ideas: [],
422
+ lastUpdated: '',
423
+ }
407
424
 
408
425
  const newIdea = {
409
426
  id: `idea_${Date.now().toString(36)}`,
410
427
  text,
411
- status: 'pending',
412
- priority,
413
- tags,
428
+ status: 'pending' as const,
429
+ priority: (priority || 'medium') as 'low' | 'medium' | 'high',
430
+ tags: tags as string[],
414
431
  addedAt: new Date().toISOString(),
415
432
  }
416
433
 
@@ -446,15 +463,17 @@ export function createExtendedRoutes(): Hono {
446
463
  for (const id of projectIds) {
447
464
  const projectPath = getProjectPath(id)
448
465
 
449
- const state = await readJsonFile<any>(path.join(projectPath, 'storage/state.json'))
450
- const queue = await readJsonFile<any>(path.join(projectPath, 'storage/queue.json'))
451
- const ideas = await readJsonFile<any>(path.join(projectPath, 'storage/ideas.json'))
452
- const shipped = await readJsonFile<any>(path.join(projectPath, 'storage/shipped.json'))
466
+ const state = await readJsonFile<StateJson>(path.join(projectPath, 'storage/state.json'))
467
+ const queue = await readJsonFile<QueueJson>(path.join(projectPath, 'storage/queue.json'))
468
+ const ideas = await readJsonFile<IdeasJson>(path.join(projectPath, 'storage/ideas.json'))
469
+ const shipped = await readJsonFile<ShippedJson>(
470
+ path.join(projectPath, 'storage/shipped.json')
471
+ )
453
472
 
454
473
  if (state?.currentTask) activeProjects++
455
474
 
456
- totalTasks += queue?.tasks?.filter((t: any) => !t.completed)?.length || 0
457
- totalIdeas += ideas?.ideas?.filter((i: any) => i.status === 'pending')?.length || 0
475
+ totalTasks += queue?.tasks?.filter((t: QueueTask) => !t.completed)?.length || 0
476
+ totalIdeas += ideas?.ideas?.filter((i) => i.status === 'pending')?.length || 0
458
477
  totalShipped += shipped?.shipped?.length || 0
459
478
  }
460
479
 
@@ -499,16 +518,16 @@ export function createExtendedRoutes(): Hono {
499
518
  }
500
519
 
501
520
  // Find active/paused task
502
- let activeProject: any = null
503
- let activeTask: any = null
504
- let pausedTask: any = null
521
+ let activeProject: { id: string; name: string; path: string | undefined } | null = null
522
+ let activeTask: (StateTask & { duration?: string }) | null = null
523
+ let pausedTask: StateTask | null = null
505
524
 
506
525
  // If we have a target project, only check that one
507
526
  const idsToCheck = targetProjectId ? [targetProjectId] : projectIds
508
527
 
509
528
  for (const id of idsToCheck) {
510
529
  const projectPath = getProjectPath(id)
511
- const state = await readJsonFile<any>(path.join(projectPath, 'storage/state.json'))
530
+ const state = await readJsonFile<StateJson>(path.join(projectPath, 'storage/state.json'))
512
531
  const config = await getProjectConfig(id)
513
532
 
514
533
  if (state?.currentTask) {
@@ -267,8 +267,8 @@ class SyncService {
267
267
  this.globalPath,
268
268
  localConfig?.verification
269
269
  )
270
- } catch {
271
- // Verification is non-critical don't fail sync
270
+ } catch (error) {
271
+ log.debug('Verification failed (non-critical)', { error: getErrorMessage(error) })
272
272
  }
273
273
 
274
274
  return {
@@ -395,8 +395,8 @@ class SyncService {
395
395
  cwd: this.projectPath,
396
396
  })
397
397
  data.weeklyCommits = parseInt(weekly.trim(), 10) || 0
398
- } catch {
399
- // Not a git repo - use defaults
398
+ } catch (error) {
399
+ log.debug('Git analysis failed (not a git repo?)', { error: getErrorMessage(error) })
400
400
  }
401
401
 
402
402
  return data
@@ -424,7 +424,8 @@ class SyncService {
424
424
  { cwd: this.projectPath }
425
425
  )
426
426
  stats.fileCount = parseInt(stdout.trim(), 10) || 0
427
- } catch {
427
+ } catch (error) {
428
+ log.debug('File count failed', { path: this.projectPath, error: getErrorMessage(error) })
428
429
  stats.fileCount = 0
429
430
  }
430
431
 
@@ -453,8 +454,8 @@ class SyncService {
453
454
  } else {
454
455
  stats.languages.push('JavaScript')
455
456
  }
456
- } catch {
457
- // No package.json
457
+ } catch (error) {
458
+ log.debug('No package.json found', { path: this.projectPath, error: getErrorMessage(error) })
458
459
  }
459
460
 
460
461
  // Check other ecosystems
@@ -620,8 +621,8 @@ class SyncService {
620
621
  await fs.unlink(path.join(agentsPath, file))
621
622
  }
622
623
  }
623
- } catch {
624
- // Directory might not exist yet
624
+ } catch (error) {
625
+ log.debug('Failed to purge old agents', { path: agentsPath, error: getErrorMessage(error) })
625
626
  }
626
627
 
627
628
  // Workflow agents (always generated) - IN PARALLEL
@@ -714,8 +715,11 @@ class SyncService {
714
715
  )
715
716
  content = await fs.readFile(templatePath, 'utf-8')
716
717
  content = await this.resolveTemplateIncludes(content)
717
- } catch {
718
- // Generate minimal agent
718
+ } catch (error) {
719
+ log.debug('Workflow agent template not found, generating minimal', {
720
+ name,
721
+ error: getErrorMessage(error),
722
+ })
719
723
  content = this.generateMinimalWorkflowAgent(name)
720
724
  }
721
725
 
@@ -749,8 +753,11 @@ class SyncService {
749
753
  content = content.replace('{projectName}', stats.name)
750
754
  content = content.replace('{frameworks}', stack.frameworks.join(', ') || 'None detected')
751
755
  content = content.replace('{ecosystem}', stats.ecosystem)
752
- } catch {
753
- // Generate minimal agent
756
+ } catch (error) {
757
+ log.debug('Domain agent template not found, generating minimal', {
758
+ name,
759
+ error: getErrorMessage(error),
760
+ })
754
761
  content = this.generateMinimalDomainAgent(name, stats, stack)
755
762
  }
756
763
 
@@ -839,8 +846,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
839
846
  path.join(this.globalPath, 'config', 'skills.json'),
840
847
  JSON.stringify(skillsConfig, null, 2),
841
848
  'utf-8'
842
- ).catch(() => {
843
- // Best effort
849
+ ).catch((error) => {
850
+ log.debug('Failed to write skills.json', { error: getErrorMessage(error) })
844
851
  })
845
852
 
846
853
  return skills
@@ -986,8 +993,11 @@ You are the ${name} expert for this project. Apply best practices for the detect
986
993
  let existing: Record<string, unknown> = {}
987
994
  try {
988
995
  existing = JSON.parse(await fs.readFile(projectJsonPath, 'utf-8'))
989
- } catch {
990
- // No existing file
996
+ } catch (error) {
997
+ log.debug('No existing project.json', {
998
+ path: projectJsonPath,
999
+ error: getErrorMessage(error),
1000
+ })
991
1001
  }
992
1002
 
993
1003
  const updated = {
@@ -1024,8 +1034,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
1024
1034
  let state: Record<string, unknown> = {}
1025
1035
  try {
1026
1036
  state = JSON.parse(await fs.readFile(statePath, 'utf-8'))
1027
- } catch {
1028
- // No existing file
1037
+ } catch (error) {
1038
+ log.debug('No existing state.json', { path: statePath, error: getErrorMessage(error) })
1029
1039
  }
1030
1040
 
1031
1041
  // Update with enterprise fields
@@ -1062,8 +1072,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
1062
1072
  this.projectPath,
1063
1073
  state as import('../schemas/state').StateJson
1064
1074
  )
1065
- } catch {
1066
- // Silently fail - local state is optional
1075
+ } catch (error) {
1076
+ log.debug('Local state generation failed (optional)', { error: getErrorMessage(error) })
1067
1077
  }
1068
1078
  }
1069
1079
 
@@ -1114,8 +1124,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
1114
1124
  const filePath = path.join(this.globalPath, file)
1115
1125
  const content = await fs.readFile(filePath, 'utf-8')
1116
1126
  filteredChars += content.length
1117
- } catch {
1118
- // File might not exist, skip
1127
+ } catch (error) {
1128
+ log.debug('Context file not found for metrics', { file, error: getErrorMessage(error) })
1119
1129
  }
1120
1130
  }
1121
1131
 
@@ -1125,8 +1135,11 @@ You are the ${name} expert for this project. Apply best practices for the detect
1125
1135
  const agentPath = path.join(this.globalPath, 'agents', `${agent.name}.md`)
1126
1136
  const content = await fs.readFile(agentPath, 'utf-8')
1127
1137
  filteredChars += content.length
1128
- } catch {
1129
- // Skip if not found
1138
+ } catch (error) {
1139
+ log.debug('Agent file not found for metrics', {
1140
+ agent: agent.name,
1141
+ error: getErrorMessage(error),
1142
+ })
1130
1143
  }
1131
1144
  }
1132
1145
 
@@ -1152,8 +1165,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
1152
1165
  agents: agents.filter((a) => a.type === 'domain').map((a) => a.name),
1153
1166
  })
1154
1167
  } catch (error) {
1155
- // Non-blocking - metrics are nice to have
1156
- console.error('Warning: Failed to record metrics:', getErrorMessage(error))
1168
+ log.debug('Failed to record sync metrics', { error: getErrorMessage(error) })
1157
1169
  }
1158
1170
 
1159
1171
  return {
@@ -1172,7 +1184,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
1172
1184
  try {
1173
1185
  await fs.access(path.join(this.projectPath, filename))
1174
1186
  return true
1175
- } catch {
1187
+ } catch (error) {
1188
+ log.debug('File not found', { filename, error: getErrorMessage(error) })
1176
1189
  return false
1177
1190
  }
1178
1191
  }
@@ -1183,7 +1196,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
1183
1196
  const pkgPath = path.join(__dirname, '..', '..', 'package.json')
1184
1197
  const pkg = JSON.parse(await fs.readFile(pkgPath, 'utf-8'))
1185
1198
  return pkg.version || '0.0.0'
1186
- } catch {
1199
+ } catch (error) {
1200
+ log.debug('Failed to read CLI version', { error: getErrorMessage(error) })
1187
1201
  return '0.0.0'
1188
1202
  }
1189
1203
  }
@@ -3,7 +3,7 @@
3
3
  * Types for HTTP server and SSE modules.
4
4
  */
5
5
 
6
- import type { Hono } from 'hono'
6
+ import type { Context, Hono } from 'hono'
7
7
 
8
8
  // =============================================================================
9
9
  // Server Types
@@ -36,8 +36,7 @@ export interface SSEClient {
36
36
  }
37
37
 
38
38
  export interface SSEManager {
39
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
40
- handleConnection: (c: any) => Response
39
+ handleConnection: (c: Context) => Response
41
40
  broadcast: (event: string, data: unknown) => void
42
41
  getClientCount: () => number
43
42
  }