prjct-cli 1.12.0 → 1.14.0
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 +89 -0
- package/core/__tests__/agentic/analysis-injection.test.ts +377 -0
- package/core/__tests__/domain/velocity.test.ts +623 -0
- package/core/agentic/anti-hallucination.ts +23 -1
- package/core/agentic/orchestrator-executor.ts +59 -3
- package/core/agentic/prompt-builder.ts +53 -1
- package/core/commands/command-data.ts +17 -0
- package/core/commands/commands.ts +12 -0
- package/core/commands/register.ts +6 -0
- package/core/commands/velocity.ts +149 -0
- package/core/domain/velocity.ts +470 -0
- package/core/index.ts +1 -0
- package/core/schemas/index.ts +2 -0
- package/core/schemas/velocity.ts +103 -0
- package/core/storage/index.ts +2 -1
- package/core/storage/velocity-storage.ts +149 -0
- package/core/types/agentic.ts +33 -0
- package/core/types/index.ts +2 -0
- package/dist/bin/prjct.mjs +1103 -362
- package/package.json +1 -1
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Velocity Storage (PRJ-296)
|
|
3
|
+
*
|
|
4
|
+
* Manages velocity metrics with write-through pattern:
|
|
5
|
+
* - storage/velocity.json → source of truth
|
|
6
|
+
* - context/velocity.md → Claude-readable summary
|
|
7
|
+
*
|
|
8
|
+
* Extends StorageManager for consistency with existing storage classes.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { VelocityMetrics } from '../schemas/velocity'
|
|
12
|
+
import { DEFAULT_VELOCITY_METRICS } from '../schemas/velocity'
|
|
13
|
+
import { StorageManager } from './storage-manager'
|
|
14
|
+
|
|
15
|
+
// =============================================================================
|
|
16
|
+
// Types
|
|
17
|
+
// =============================================================================
|
|
18
|
+
|
|
19
|
+
interface VelocityStoreData {
|
|
20
|
+
metrics: VelocityMetrics
|
|
21
|
+
lastUpdated: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// =============================================================================
|
|
25
|
+
// Velocity Storage
|
|
26
|
+
// =============================================================================
|
|
27
|
+
|
|
28
|
+
class VelocityStorage extends StorageManager<VelocityStoreData> {
|
|
29
|
+
constructor() {
|
|
30
|
+
super('velocity.json')
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
protected getDefault(): VelocityStoreData {
|
|
34
|
+
return {
|
|
35
|
+
metrics: DEFAULT_VELOCITY_METRICS,
|
|
36
|
+
lastUpdated: '',
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
protected getMdFilename(): string {
|
|
41
|
+
return 'velocity.md'
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
protected getLayer(): string {
|
|
45
|
+
return 'progress'
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
protected getEventType(action: 'update' | 'create' | 'delete'): string {
|
|
49
|
+
return `velocity.${action}d`
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
protected toMarkdown(data: VelocityStoreData): string {
|
|
53
|
+
const { metrics } = data
|
|
54
|
+
const lines = ['# Velocity', '']
|
|
55
|
+
|
|
56
|
+
if (metrics.sprints.length === 0) {
|
|
57
|
+
lines.push('_No velocity data yet. Complete tasks with estimates to build velocity history._')
|
|
58
|
+
lines.push('')
|
|
59
|
+
return lines.join('\n')
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Summary
|
|
63
|
+
lines.push(`**Average**: ${metrics.averageVelocity} pts/sprint`)
|
|
64
|
+
lines.push(`**Trend**: ${formatTrendIcon(metrics.velocityTrend)} ${metrics.velocityTrend}`)
|
|
65
|
+
lines.push(`**Estimation Accuracy**: ${metrics.estimationAccuracy}%`)
|
|
66
|
+
lines.push('')
|
|
67
|
+
|
|
68
|
+
// Sprint table
|
|
69
|
+
lines.push('## Sprint History')
|
|
70
|
+
lines.push('')
|
|
71
|
+
lines.push('| Sprint | Points | Tasks | Accuracy | Variance |')
|
|
72
|
+
lines.push('|--------|--------|-------|----------|----------|')
|
|
73
|
+
|
|
74
|
+
const recentSprints = metrics.sprints.slice(-6)
|
|
75
|
+
for (const sprint of recentSprints) {
|
|
76
|
+
lines.push(
|
|
77
|
+
`| ${sprint.sprintNumber} | ${sprint.pointsCompleted} | ${sprint.tasksCompleted} | ${sprint.estimationAccuracy}% | ${sprint.avgVariance > 0 ? '+' : ''}${sprint.avgVariance}% |`
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
lines.push('')
|
|
81
|
+
|
|
82
|
+
// Patterns
|
|
83
|
+
if (metrics.underEstimated.length > 0 || metrics.overEstimated.length > 0) {
|
|
84
|
+
lines.push('## Estimation Patterns')
|
|
85
|
+
lines.push('')
|
|
86
|
+
|
|
87
|
+
for (const p of metrics.underEstimated) {
|
|
88
|
+
lines.push(
|
|
89
|
+
`- ⚠ **${p.category}**: underestimated by avg ${p.avgVariance}% (${p.taskCount} tasks)`
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
for (const p of metrics.overEstimated) {
|
|
93
|
+
lines.push(
|
|
94
|
+
`- ✓ **${p.category}**: overestimated by avg ${p.avgVariance}% (${p.taskCount} tasks)`
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
lines.push('')
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return lines.join('\n')
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ===========================================================================
|
|
104
|
+
// Domain Methods
|
|
105
|
+
// ===========================================================================
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Save computed velocity metrics.
|
|
109
|
+
*/
|
|
110
|
+
async saveMetrics(projectId: string, metrics: VelocityMetrics): Promise<void> {
|
|
111
|
+
await this.write(projectId, {
|
|
112
|
+
metrics,
|
|
113
|
+
lastUpdated: metrics.lastUpdated,
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
await this.publishEntityEvent(projectId, 'velocity', 'updated', {
|
|
117
|
+
averageVelocity: metrics.averageVelocity,
|
|
118
|
+
trend: metrics.velocityTrend,
|
|
119
|
+
sprintCount: metrics.sprints.length,
|
|
120
|
+
})
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Get current velocity metrics.
|
|
125
|
+
*/
|
|
126
|
+
async getMetrics(projectId: string): Promise<VelocityMetrics> {
|
|
127
|
+
const data = await this.read(projectId)
|
|
128
|
+
return data.metrics
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// =============================================================================
|
|
133
|
+
// Helpers
|
|
134
|
+
// =============================================================================
|
|
135
|
+
|
|
136
|
+
function formatTrendIcon(trend: string): string {
|
|
137
|
+
switch (trend) {
|
|
138
|
+
case 'improving':
|
|
139
|
+
return '↑'
|
|
140
|
+
case 'declining':
|
|
141
|
+
return '↓'
|
|
142
|
+
default:
|
|
143
|
+
return '→'
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export const velocityStorage = new VelocityStorage()
|
|
148
|
+
export default velocityStorage
|
|
149
|
+
export type { VelocityStoreData }
|
package/core/types/agentic.ts
CHANGED
|
@@ -724,4 +724,37 @@ export interface OrchestratorContext {
|
|
|
724
724
|
}
|
|
725
725
|
/** Real codebase context gathered proactively */
|
|
726
726
|
realContext?: RealCodebaseContext
|
|
727
|
+
/** Sealed/active analysis from PRJ-263 storage — injected into prompt context (PRJ-260) */
|
|
728
|
+
sealedAnalysis?: SealedAnalysisContext | null
|
|
729
|
+
/** Velocity context for estimation guidance (PRJ-296) */
|
|
730
|
+
velocityContext?: string | null
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
/**
|
|
734
|
+
* Subset of analysis data injected into prompt context.
|
|
735
|
+
* Extracted from AnalysisSchema to avoid coupling types to storage schema.
|
|
736
|
+
*
|
|
737
|
+
* @see PRJ-260
|
|
738
|
+
*/
|
|
739
|
+
export interface SealedAnalysisContext {
|
|
740
|
+
/** Programming languages detected */
|
|
741
|
+
languages: string[]
|
|
742
|
+
/** Frameworks detected */
|
|
743
|
+
frameworks: string[]
|
|
744
|
+
/** Package manager (e.g., 'bun', 'npm', 'pnpm') */
|
|
745
|
+
packageManager?: string
|
|
746
|
+
/** Source directory */
|
|
747
|
+
sourceDir?: string
|
|
748
|
+
/** Test directory */
|
|
749
|
+
testDir?: string
|
|
750
|
+
/** Total files analyzed */
|
|
751
|
+
fileCount: number
|
|
752
|
+
/** Code patterns found */
|
|
753
|
+
patterns: Array<{ name: string; description: string; location?: string }>
|
|
754
|
+
/** Anti-patterns found */
|
|
755
|
+
antiPatterns: Array<{ issue: string; file: string; suggestion: string }>
|
|
756
|
+
/** Lifecycle status */
|
|
757
|
+
status: 'draft' | 'verified' | 'sealed'
|
|
758
|
+
/** Git commit hash when analysis was performed */
|
|
759
|
+
commitHash?: string
|
|
727
760
|
}
|