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.
@@ -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 }
@@ -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
  }
@@ -81,6 +81,8 @@ export type {
81
81
  RealCodebaseContext,
82
82
  ReasoningResult,
83
83
  ReasoningStep,
84
+ // Sealed analysis context (PRJ-260)
85
+ SealedAnalysisContext,
84
86
  SimpleExecutionResult,
85
87
  SkillContext,
86
88
  SmartContextProjectState,