prjct-cli 1.6.6 → 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 +29 -0
- package/assets/statusline/default-config.json +1 -1
- 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/dist/bin/prjct.mjs +57 -21
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
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
|
+
|
|
3
32
|
## [1.6.6] - 2026-02-07
|
|
4
33
|
|
|
5
34
|
### Refactoring
|
|
@@ -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
|
}
|
package/core/types/storage.ts
CHANGED
|
@@ -18,6 +18,127 @@ export interface Storage {
|
|
|
18
18
|
exists(path: string[]): Promise<boolean>
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
// =============================================================================
|
|
22
|
+
// Project JSON Types (project.json)
|
|
23
|
+
// =============================================================================
|
|
24
|
+
|
|
25
|
+
export interface ProjectJson {
|
|
26
|
+
projectId: string
|
|
27
|
+
repoPath?: string
|
|
28
|
+
path?: string
|
|
29
|
+
name?: string
|
|
30
|
+
version?: string
|
|
31
|
+
cliVersion?: string
|
|
32
|
+
techStack?: string[]
|
|
33
|
+
fileCount?: number
|
|
34
|
+
commitCount?: number
|
|
35
|
+
stack?: string
|
|
36
|
+
currentBranch?: string
|
|
37
|
+
hasUncommittedChanges?: boolean
|
|
38
|
+
createdAt?: string
|
|
39
|
+
lastSync?: string
|
|
40
|
+
integrations?: {
|
|
41
|
+
linear?: {
|
|
42
|
+
enabled: boolean
|
|
43
|
+
authMode?: string
|
|
44
|
+
teamId?: string
|
|
45
|
+
teamName?: string
|
|
46
|
+
teamKey?: string
|
|
47
|
+
setupAt?: string
|
|
48
|
+
}
|
|
49
|
+
jira?: {
|
|
50
|
+
enabled: boolean
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
lastSyncCommit?: string
|
|
54
|
+
lastSyncBranch?: string
|
|
55
|
+
hooks?: {
|
|
56
|
+
enabled: boolean
|
|
57
|
+
strategy?: string
|
|
58
|
+
hooks?: unknown[]
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// =============================================================================
|
|
63
|
+
// State JSON Types (state.json)
|
|
64
|
+
// =============================================================================
|
|
65
|
+
|
|
66
|
+
export interface StateTask {
|
|
67
|
+
id: string
|
|
68
|
+
description: string
|
|
69
|
+
type?: string
|
|
70
|
+
status: string
|
|
71
|
+
startedAt: string
|
|
72
|
+
shippedAt?: string
|
|
73
|
+
prUrl?: string
|
|
74
|
+
subtasks?: Array<{ description: string; status: string }>
|
|
75
|
+
currentSubtaskIndex?: number
|
|
76
|
+
parentDescription?: string
|
|
77
|
+
branch?: string
|
|
78
|
+
linearId?: string | null
|
|
79
|
+
linearUuid?: string | null
|
|
80
|
+
duration?: string
|
|
81
|
+
sessionId?: string
|
|
82
|
+
featureId?: string
|
|
83
|
+
pausedAt?: string
|
|
84
|
+
pauseReason?: string
|
|
85
|
+
expectedValue?: {
|
|
86
|
+
type: string
|
|
87
|
+
impact: string
|
|
88
|
+
successCriteria: string[]
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface StateJson {
|
|
93
|
+
currentTask: StateTask | null
|
|
94
|
+
pausedTasks?: StateTask[]
|
|
95
|
+
previousTask: StateTask | null
|
|
96
|
+
lastUpdated?: string
|
|
97
|
+
projectId?: string
|
|
98
|
+
stack?: { language: string; framework: string }
|
|
99
|
+
domains?: Record<string, boolean>
|
|
100
|
+
projectType?: string
|
|
101
|
+
metrics?: { totalFiles: number }
|
|
102
|
+
lastSync?: string
|
|
103
|
+
context?: {
|
|
104
|
+
lastSession: string
|
|
105
|
+
lastAction: string
|
|
106
|
+
nextAction: string
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// =============================================================================
|
|
111
|
+
// Queue JSON Types (queue.json)
|
|
112
|
+
// =============================================================================
|
|
113
|
+
|
|
114
|
+
export interface QueueTask {
|
|
115
|
+
id: string
|
|
116
|
+
description: string
|
|
117
|
+
type?: string
|
|
118
|
+
priority?: string
|
|
119
|
+
section?: string
|
|
120
|
+
createdAt: string
|
|
121
|
+
completed?: boolean
|
|
122
|
+
completedAt?: string
|
|
123
|
+
featureId?: string
|
|
124
|
+
featureName?: string
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export interface QueueJson {
|
|
128
|
+
tasks: QueueTask[]
|
|
129
|
+
lastUpdated?: string
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// =============================================================================
|
|
133
|
+
// Roadmap JSON Types (roadmap.json)
|
|
134
|
+
// =============================================================================
|
|
135
|
+
|
|
136
|
+
export interface RoadmapJson {
|
|
137
|
+
features: unknown[]
|
|
138
|
+
backlog: unknown[]
|
|
139
|
+
lastUpdated: string
|
|
140
|
+
}
|
|
141
|
+
|
|
21
142
|
// =============================================================================
|
|
22
143
|
// Shipped Storage Types
|
|
23
144
|
// =============================================================================
|
package/dist/bin/prjct.mjs
CHANGED
|
@@ -22478,7 +22478,8 @@ var init_sync_service = __esm({
|
|
|
22478
22478
|
this.globalPath,
|
|
22479
22479
|
localConfig?.verification
|
|
22480
22480
|
);
|
|
22481
|
-
} catch {
|
|
22481
|
+
} catch (error) {
|
|
22482
|
+
logger_default.debug("Verification failed (non-critical)", { error: getErrorMessage(error) });
|
|
22482
22483
|
}
|
|
22483
22484
|
return {
|
|
22484
22485
|
success: true,
|
|
@@ -22583,7 +22584,8 @@ var init_sync_service = __esm({
|
|
|
22583
22584
|
cwd: this.projectPath
|
|
22584
22585
|
});
|
|
22585
22586
|
data.weeklyCommits = parseInt(weekly.trim(), 10) || 0;
|
|
22586
|
-
} catch {
|
|
22587
|
+
} catch (error) {
|
|
22588
|
+
logger_default.debug("Git analysis failed (not a git repo?)", { error: getErrorMessage(error) });
|
|
22587
22589
|
}
|
|
22588
22590
|
return data;
|
|
22589
22591
|
}
|
|
@@ -22606,7 +22608,8 @@ var init_sync_service = __esm({
|
|
|
22606
22608
|
{ cwd: this.projectPath }
|
|
22607
22609
|
);
|
|
22608
22610
|
stats.fileCount = parseInt(stdout.trim(), 10) || 0;
|
|
22609
|
-
} catch {
|
|
22611
|
+
} catch (error) {
|
|
22612
|
+
logger_default.debug("File count failed", { path: this.projectPath, error: getErrorMessage(error) });
|
|
22610
22613
|
stats.fileCount = 0;
|
|
22611
22614
|
}
|
|
22612
22615
|
try {
|
|
@@ -22628,7 +22631,8 @@ var init_sync_service = __esm({
|
|
|
22628
22631
|
} else {
|
|
22629
22632
|
stats.languages.push("JavaScript");
|
|
22630
22633
|
}
|
|
22631
|
-
} catch {
|
|
22634
|
+
} catch (error) {
|
|
22635
|
+
logger_default.debug("No package.json found", { path: this.projectPath, error: getErrorMessage(error) });
|
|
22632
22636
|
}
|
|
22633
22637
|
if (await this.fileExists("Cargo.toml")) {
|
|
22634
22638
|
stats.ecosystem = "Rust";
|
|
@@ -22763,7 +22767,8 @@ var init_sync_service = __esm({
|
|
|
22763
22767
|
await fs45.unlink(path49.join(agentsPath, file));
|
|
22764
22768
|
}
|
|
22765
22769
|
}
|
|
22766
|
-
} catch {
|
|
22770
|
+
} catch (error) {
|
|
22771
|
+
logger_default.debug("Failed to purge old agents", { path: agentsPath, error: getErrorMessage(error) });
|
|
22767
22772
|
}
|
|
22768
22773
|
const workflowAgents = ["prjct-workflow", "prjct-planner", "prjct-shipper"];
|
|
22769
22774
|
await Promise.all(workflowAgents.map((name) => this.generateWorkflowAgent(name, agentsPath)));
|
|
@@ -22839,7 +22844,11 @@ var init_sync_service = __esm({
|
|
|
22839
22844
|
);
|
|
22840
22845
|
content = await fs45.readFile(templatePath, "utf-8");
|
|
22841
22846
|
content = await this.resolveTemplateIncludes(content);
|
|
22842
|
-
} catch {
|
|
22847
|
+
} catch (error) {
|
|
22848
|
+
logger_default.debug("Workflow agent template not found, generating minimal", {
|
|
22849
|
+
name,
|
|
22850
|
+
error: getErrorMessage(error)
|
|
22851
|
+
});
|
|
22843
22852
|
content = this.generateMinimalWorkflowAgent(name);
|
|
22844
22853
|
}
|
|
22845
22854
|
await fs45.writeFile(path49.join(agentsPath, `${name}.md`), content, "utf-8");
|
|
@@ -22861,7 +22870,11 @@ var init_sync_service = __esm({
|
|
|
22861
22870
|
content = content.replace("{projectName}", stats.name);
|
|
22862
22871
|
content = content.replace("{frameworks}", stack.frameworks.join(", ") || "None detected");
|
|
22863
22872
|
content = content.replace("{ecosystem}", stats.ecosystem);
|
|
22864
|
-
} catch {
|
|
22873
|
+
} catch (error) {
|
|
22874
|
+
logger_default.debug("Domain agent template not found, generating minimal", {
|
|
22875
|
+
name,
|
|
22876
|
+
error: getErrorMessage(error)
|
|
22877
|
+
});
|
|
22865
22878
|
content = this.generateMinimalDomainAgent(name, stats, stack);
|
|
22866
22879
|
}
|
|
22867
22880
|
await fs45.writeFile(path49.join(agentsPath, `${name}.md`), content, "utf-8");
|
|
@@ -22936,7 +22949,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
22936
22949
|
path49.join(this.globalPath, "config", "skills.json"),
|
|
22937
22950
|
JSON.stringify(skillsConfig, null, 2),
|
|
22938
22951
|
"utf-8"
|
|
22939
|
-
).catch(() => {
|
|
22952
|
+
).catch((error) => {
|
|
22953
|
+
logger_default.debug("Failed to write skills.json", { error: getErrorMessage(error) });
|
|
22940
22954
|
});
|
|
22941
22955
|
return skills;
|
|
22942
22956
|
}
|
|
@@ -23044,7 +23058,11 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
23044
23058
|
let existing = {};
|
|
23045
23059
|
try {
|
|
23046
23060
|
existing = JSON.parse(await fs45.readFile(projectJsonPath, "utf-8"));
|
|
23047
|
-
} catch {
|
|
23061
|
+
} catch (error) {
|
|
23062
|
+
logger_default.debug("No existing project.json", {
|
|
23063
|
+
path: projectJsonPath,
|
|
23064
|
+
error: getErrorMessage(error)
|
|
23065
|
+
});
|
|
23048
23066
|
}
|
|
23049
23067
|
const updated = {
|
|
23050
23068
|
...existing,
|
|
@@ -23075,7 +23093,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
23075
23093
|
let state = {};
|
|
23076
23094
|
try {
|
|
23077
23095
|
state = JSON.parse(await fs45.readFile(statePath, "utf-8"));
|
|
23078
|
-
} catch {
|
|
23096
|
+
} catch (error) {
|
|
23097
|
+
logger_default.debug("No existing state.json", { path: statePath, error: getErrorMessage(error) });
|
|
23079
23098
|
}
|
|
23080
23099
|
state.projectId = this.projectId;
|
|
23081
23100
|
state.stack = {
|
|
@@ -23107,7 +23126,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
23107
23126
|
this.projectPath,
|
|
23108
23127
|
state
|
|
23109
23128
|
);
|
|
23110
|
-
} catch {
|
|
23129
|
+
} catch (error) {
|
|
23130
|
+
logger_default.debug("Local state generation failed (optional)", { error: getErrorMessage(error) });
|
|
23111
23131
|
}
|
|
23112
23132
|
}
|
|
23113
23133
|
// ==========================================================================
|
|
@@ -23146,7 +23166,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
23146
23166
|
const filePath = path49.join(this.globalPath, file);
|
|
23147
23167
|
const content = await fs45.readFile(filePath, "utf-8");
|
|
23148
23168
|
filteredChars += content.length;
|
|
23149
|
-
} catch {
|
|
23169
|
+
} catch (error) {
|
|
23170
|
+
logger_default.debug("Context file not found for metrics", { file, error: getErrorMessage(error) });
|
|
23150
23171
|
}
|
|
23151
23172
|
}
|
|
23152
23173
|
for (const agent of agents) {
|
|
@@ -23154,7 +23175,11 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
23154
23175
|
const agentPath = path49.join(this.globalPath, "agents", `${agent.name}.md`);
|
|
23155
23176
|
const content = await fs45.readFile(agentPath, "utf-8");
|
|
23156
23177
|
filteredChars += content.length;
|
|
23157
|
-
} catch {
|
|
23178
|
+
} catch (error) {
|
|
23179
|
+
logger_default.debug("Agent file not found for metrics", {
|
|
23180
|
+
agent: agent.name,
|
|
23181
|
+
error: getErrorMessage(error)
|
|
23182
|
+
});
|
|
23158
23183
|
}
|
|
23159
23184
|
}
|
|
23160
23185
|
const filteredSize = Math.floor(filteredChars / CHARS_PER_TOKEN3);
|
|
@@ -23170,7 +23195,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
23170
23195
|
agents: agents.filter((a) => a.type === "domain").map((a) => a.name)
|
|
23171
23196
|
});
|
|
23172
23197
|
} catch (error) {
|
|
23173
|
-
|
|
23198
|
+
logger_default.debug("Failed to record sync metrics", { error: getErrorMessage(error) });
|
|
23174
23199
|
}
|
|
23175
23200
|
return {
|
|
23176
23201
|
duration,
|
|
@@ -23186,7 +23211,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
23186
23211
|
try {
|
|
23187
23212
|
await fs45.access(path49.join(this.projectPath, filename));
|
|
23188
23213
|
return true;
|
|
23189
|
-
} catch {
|
|
23214
|
+
} catch (error) {
|
|
23215
|
+
logger_default.debug("File not found", { filename, error: getErrorMessage(error) });
|
|
23190
23216
|
return false;
|
|
23191
23217
|
}
|
|
23192
23218
|
}
|
|
@@ -23195,7 +23221,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
23195
23221
|
const pkgPath = path49.join(__dirname, "..", "..", "package.json");
|
|
23196
23222
|
const pkg = JSON.parse(await fs45.readFile(pkgPath, "utf-8"));
|
|
23197
23223
|
return pkg.version || "0.0.0";
|
|
23198
|
-
} catch {
|
|
23224
|
+
} catch (error) {
|
|
23225
|
+
logger_default.debug("Failed to read CLI version", { error: getErrorMessage(error) });
|
|
23199
23226
|
return "0.0.0";
|
|
23200
23227
|
}
|
|
23201
23228
|
}
|
|
@@ -28719,7 +28746,7 @@ var require_package = __commonJS({
|
|
|
28719
28746
|
"package.json"(exports, module) {
|
|
28720
28747
|
module.exports = {
|
|
28721
28748
|
name: "prjct-cli",
|
|
28722
|
-
version: "1.6.
|
|
28749
|
+
version: "1.6.7",
|
|
28723
28750
|
description: "Context layer for AI agents. Project context for Claude Code, Gemini CLI, and more.",
|
|
28724
28751
|
main: "core/index.ts",
|
|
28725
28752
|
bin: {
|
|
@@ -29397,7 +29424,9 @@ function createExtendedRoutes() {
|
|
|
29397
29424
|
const state = await readJsonFile2(path8.join(projectPath, "storage/state.json"));
|
|
29398
29425
|
const queue = await readJsonFile2(path8.join(projectPath, "storage/queue.json"));
|
|
29399
29426
|
const ideas = await readJsonFile2(path8.join(projectPath, "storage/ideas.json"));
|
|
29400
|
-
const shipped = await readJsonFile2(
|
|
29427
|
+
const shipped = await readJsonFile2(
|
|
29428
|
+
path8.join(projectPath, "storage/shipped.json")
|
|
29429
|
+
);
|
|
29401
29430
|
const currentTask = state?.currentTask;
|
|
29402
29431
|
const duration = await calculateDuration2(currentTask?.startedAt);
|
|
29403
29432
|
return {
|
|
@@ -29547,6 +29576,7 @@ function createExtendedRoutes() {
|
|
|
29547
29576
|
const resumedTask = {
|
|
29548
29577
|
id: state.previousTask.id,
|
|
29549
29578
|
description: state.previousTask.description,
|
|
29579
|
+
status: "active",
|
|
29550
29580
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
29551
29581
|
sessionId: `sess_${Date.now().toString(36)}`
|
|
29552
29582
|
};
|
|
@@ -29588,6 +29618,7 @@ function createExtendedRoutes() {
|
|
|
29588
29618
|
const newTask = {
|
|
29589
29619
|
id: task.id,
|
|
29590
29620
|
description: task.description,
|
|
29621
|
+
status: "active",
|
|
29591
29622
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
29592
29623
|
sessionId: `sess_${Date.now().toString(36)}`,
|
|
29593
29624
|
featureId: task.featureId
|
|
@@ -29617,12 +29648,15 @@ function createExtendedRoutes() {
|
|
|
29617
29648
|
if (!text) {
|
|
29618
29649
|
return c.json({ success: false, error: "text required" }, 400);
|
|
29619
29650
|
}
|
|
29620
|
-
const ideas = await readJsonFile2(ideasPath) || {
|
|
29651
|
+
const ideas = await readJsonFile2(ideasPath) || {
|
|
29652
|
+
ideas: [],
|
|
29653
|
+
lastUpdated: ""
|
|
29654
|
+
};
|
|
29621
29655
|
const newIdea = {
|
|
29622
29656
|
id: `idea_${Date.now().toString(36)}`,
|
|
29623
29657
|
text,
|
|
29624
29658
|
status: "pending",
|
|
29625
|
-
priority,
|
|
29659
|
+
priority: priority || "medium",
|
|
29626
29660
|
tags,
|
|
29627
29661
|
addedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
29628
29662
|
};
|
|
@@ -29652,7 +29686,9 @@ function createExtendedRoutes() {
|
|
|
29652
29686
|
const state = await readJsonFile2(path8.join(projectPath, "storage/state.json"));
|
|
29653
29687
|
const queue = await readJsonFile2(path8.join(projectPath, "storage/queue.json"));
|
|
29654
29688
|
const ideas = await readJsonFile2(path8.join(projectPath, "storage/ideas.json"));
|
|
29655
|
-
const shipped = await readJsonFile2(
|
|
29689
|
+
const shipped = await readJsonFile2(
|
|
29690
|
+
path8.join(projectPath, "storage/shipped.json")
|
|
29691
|
+
);
|
|
29656
29692
|
if (state?.currentTask) activeProjects++;
|
|
29657
29693
|
totalTasks += queue?.tasks?.filter((t) => !t.completed)?.length || 0;
|
|
29658
29694
|
totalIdeas += ideas?.ideas?.filter((i) => i.status === "pending")?.length || 0;
|