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 +38 -2
- package/assets/statusline/default-config.json +1 -1
- package/core/bus/bus.ts +2 -1
- package/core/constants/index.ts +59 -0
- package/core/server/routes-extended.ts +63 -44
- package/core/services/sync-service.ts +43 -29
- package/core/types/server.ts +2 -3
- package/core/types/storage.ts +121 -0
- package/core/utils/jsonl-helper.ts +8 -4
- package/core/utils/output.ts +18 -11
- package/dist/bin/prjct.mjs +184 -112
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,46 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [1.6.
|
|
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
|
|
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
|
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 =
|
|
49
|
+
this.historyLimit = EVENT_LIMITS.HISTORY_MAX
|
|
49
50
|
this.projectId = null
|
|
50
51
|
}
|
|
51
52
|
|
package/core/constants/index.ts
CHANGED
|
@@ -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<
|
|
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<
|
|
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<
|
|
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<
|
|
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<
|
|
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:
|
|
127
|
-
ideasCount: ideas?.ideas?.filter((i
|
|
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<
|
|
158
|
-
readJsonFile<
|
|
159
|
-
readJsonFile<
|
|
160
|
-
readJsonFile<
|
|
161
|
-
readJsonFile<
|
|
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:
|
|
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:
|
|
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:
|
|
200
|
-
ideasCount: ideas?.ideas?.filter((i
|
|
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<
|
|
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<
|
|
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<
|
|
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<
|
|
349
|
-
const queue = await readJsonFile<
|
|
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:
|
|
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<
|
|
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<
|
|
450
|
-
const queue = await readJsonFile<
|
|
451
|
-
const ideas = await readJsonFile<
|
|
452
|
-
const shipped = await readJsonFile<
|
|
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:
|
|
457
|
-
totalIdeas += ideas?.ideas?.filter((i
|
|
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:
|
|
503
|
-
let activeTask:
|
|
504
|
-
let pausedTask:
|
|
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<
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
}
|
package/core/types/server.ts
CHANGED
|
@@ -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
|
-
|
|
40
|
-
handleConnection: (c: any) => Response
|
|
39
|
+
handleConnection: (c: Context) => Response
|
|
41
40
|
broadcast: (event: string, data: unknown) => void
|
|
42
41
|
getClientCount: () => number
|
|
43
42
|
}
|