prjct-cli 0.13.2 → 0.15.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.
Files changed (193) hide show
  1. package/CHANGELOG.md +106 -0
  2. package/bin/prjct +10 -13
  3. package/core/agentic/memory-system/semantic-memories.ts +2 -1
  4. package/core/agentic/plan-mode/plan-mode.ts +2 -1
  5. package/core/agentic/prompt-builder.ts +22 -43
  6. package/core/agentic/services.ts +5 -5
  7. package/core/agentic/smart-context.ts +7 -2
  8. package/core/command-registry/core-commands.ts +54 -29
  9. package/core/command-registry/optional-commands.ts +64 -0
  10. package/core/command-registry/setup-commands.ts +18 -3
  11. package/core/commands/analysis.ts +21 -68
  12. package/core/commands/analytics.ts +247 -213
  13. package/core/commands/base.ts +1 -1
  14. package/core/commands/index.ts +41 -36
  15. package/core/commands/maintenance.ts +300 -31
  16. package/core/commands/planning.ts +233 -22
  17. package/core/commands/setup.ts +3 -8
  18. package/core/commands/shipping.ts +14 -18
  19. package/core/commands/types.ts +8 -6
  20. package/core/commands/workflow.ts +105 -100
  21. package/core/context/generator.ts +317 -0
  22. package/core/context-sync.ts +7 -350
  23. package/core/data/index.ts +13 -32
  24. package/core/data/md-ideas-manager.ts +155 -0
  25. package/core/data/md-queue-manager.ts +4 -3
  26. package/core/data/md-shipped-manager.ts +90 -0
  27. package/core/data/md-state-manager.ts +11 -7
  28. package/core/domain/agent-generator.ts +23 -63
  29. package/core/events/index.ts +143 -0
  30. package/core/index.ts +17 -14
  31. package/core/infrastructure/capability-installer.ts +13 -149
  32. package/core/infrastructure/migrator/project-scanner.ts +2 -1
  33. package/core/infrastructure/path-manager.ts +4 -6
  34. package/core/infrastructure/setup.ts +3 -0
  35. package/core/infrastructure/uuid-migration.ts +750 -0
  36. package/core/outcomes/recorder.ts +2 -1
  37. package/core/plugin/loader.ts +4 -7
  38. package/core/plugin/registry.ts +3 -3
  39. package/core/schemas/index.ts +23 -25
  40. package/core/schemas/state.ts +1 -0
  41. package/core/serializers/ideas-serializer.ts +187 -0
  42. package/core/serializers/index.ts +16 -0
  43. package/core/serializers/shipped-serializer.ts +108 -0
  44. package/core/session/utils.ts +3 -9
  45. package/core/storage/ideas-storage.ts +273 -0
  46. package/core/storage/index.ts +204 -0
  47. package/core/storage/queue-storage.ts +297 -0
  48. package/core/storage/shipped-storage.ts +223 -0
  49. package/core/storage/state-storage.ts +235 -0
  50. package/core/storage/storage-manager.ts +175 -0
  51. package/package.json +1 -1
  52. package/packages/web/app/api/projects/[id]/momentum/route.ts +257 -0
  53. package/packages/web/app/api/sessions/current/route.ts +132 -0
  54. package/packages/web/app/api/sessions/history/route.ts +96 -14
  55. package/packages/web/app/globals.css +5 -0
  56. package/packages/web/app/layout.tsx +2 -0
  57. package/packages/web/app/project/[id]/code/layout.tsx +18 -0
  58. package/packages/web/app/project/[id]/code/page.tsx +408 -0
  59. package/packages/web/app/project/[id]/page.tsx +359 -389
  60. package/packages/web/app/project/[id]/reports/page.tsx +59 -0
  61. package/packages/web/app/project/[id]/reports/print/page.tsx +58 -0
  62. package/packages/web/components/ActivityTimeline/ActivityTimeline.tsx +0 -1
  63. package/packages/web/components/AgentsCard/AgentsCard.tsx +64 -34
  64. package/packages/web/components/AgentsCard/AgentsCard.types.ts +1 -0
  65. package/packages/web/components/AppSidebar/AppSidebar.tsx +135 -11
  66. package/packages/web/components/BentoCard/BentoCard.constants.ts +3 -3
  67. package/packages/web/components/BentoCard/BentoCard.tsx +2 -1
  68. package/packages/web/components/BentoGrid/BentoGrid.tsx +2 -2
  69. package/packages/web/components/BlockersCard/BlockersCard.tsx +65 -57
  70. package/packages/web/components/BlockersCard/BlockersCard.types.ts +1 -0
  71. package/packages/web/components/CommandBar/CommandBar.tsx +67 -0
  72. package/packages/web/components/CommandBar/index.ts +1 -0
  73. package/packages/web/components/DashboardContent/DashboardContent.tsx +35 -5
  74. package/packages/web/components/DateGroup/DateGroup.tsx +1 -1
  75. package/packages/web/components/EmptyState/EmptyState.tsx +39 -21
  76. package/packages/web/components/EmptyState/EmptyState.types.ts +1 -0
  77. package/packages/web/components/EventRow/EventRow.tsx +4 -4
  78. package/packages/web/components/EventRow/EventRow.utils.ts +3 -3
  79. package/packages/web/components/HeroSection/HeroSection.tsx +52 -15
  80. package/packages/web/components/HeroSection/HeroSection.types.ts +4 -4
  81. package/packages/web/components/HeroSection/HeroSection.utils.ts +7 -3
  82. package/packages/web/components/IdeasCard/IdeasCard.tsx +94 -27
  83. package/packages/web/components/IdeasCard/IdeasCard.types.ts +1 -0
  84. package/packages/web/components/MasonryGrid/MasonryGrid.tsx +18 -0
  85. package/packages/web/components/MasonryGrid/index.ts +1 -0
  86. package/packages/web/components/MomentumWidget/MomentumWidget.tsx +119 -0
  87. package/packages/web/components/MomentumWidget/MomentumWidget.types.ts +16 -0
  88. package/packages/web/components/MomentumWidget/index.ts +2 -0
  89. package/packages/web/components/NowCard/NowCard.tsx +81 -56
  90. package/packages/web/components/NowCard/NowCard.types.ts +1 -0
  91. package/packages/web/components/PageHeader/PageHeader.tsx +24 -0
  92. package/packages/web/components/PageHeader/index.ts +1 -0
  93. package/packages/web/components/ProgressRing/ProgressRing.constants.ts +2 -2
  94. package/packages/web/components/ProjectAvatar/ProjectAvatar.tsx +2 -2
  95. package/packages/web/components/ProjectColorDot/ProjectColorDot.tsx +37 -0
  96. package/packages/web/components/ProjectColorDot/index.ts +1 -0
  97. package/packages/web/components/ProjectSelectorModal/ProjectSelectorModal.tsx +104 -0
  98. package/packages/web/components/ProjectSelectorModal/index.ts +1 -0
  99. package/packages/web/components/Providers/Providers.tsx +4 -1
  100. package/packages/web/components/QueueCard/QueueCard.tsx +78 -25
  101. package/packages/web/components/QueueCard/QueueCard.types.ts +1 -0
  102. package/packages/web/components/QueueCard/QueueCard.utils.ts +3 -3
  103. package/packages/web/components/RecoverCard/RecoverCard.tsx +72 -0
  104. package/packages/web/components/RecoverCard/RecoverCard.types.ts +16 -0
  105. package/packages/web/components/RecoverCard/index.ts +2 -0
  106. package/packages/web/components/RoadmapCard/RoadmapCard.tsx +101 -33
  107. package/packages/web/components/RoadmapCard/RoadmapCard.types.ts +1 -0
  108. package/packages/web/components/ShipsCard/ShipsCard.tsx +71 -28
  109. package/packages/web/components/ShipsCard/ShipsCard.types.ts +2 -0
  110. package/packages/web/components/SparklineChart/SparklineChart.tsx +20 -18
  111. package/packages/web/components/StatsMasonry/StatsMasonry.tsx +95 -0
  112. package/packages/web/components/StatsMasonry/index.ts +1 -0
  113. package/packages/web/components/StreakCard/StreakCard.tsx +37 -35
  114. package/packages/web/components/TasksCounter/TasksCounter.tsx +1 -1
  115. package/packages/web/components/TechStackBadges/TechStackBadges.tsx +12 -4
  116. package/packages/web/components/TerminalDock/DockToggleTab.tsx +29 -0
  117. package/packages/web/components/TerminalDock/TerminalDock.tsx +386 -0
  118. package/packages/web/components/TerminalDock/TerminalDockTab.tsx +130 -0
  119. package/packages/web/components/TerminalDock/TerminalTabBar.tsx +142 -0
  120. package/packages/web/components/TerminalDock/index.ts +2 -0
  121. package/packages/web/components/VelocityBadge/VelocityBadge.tsx +8 -3
  122. package/packages/web/components/VelocityCard/VelocityCard.tsx +49 -47
  123. package/packages/web/components/WeeklyReports/PrintableReport.tsx +259 -0
  124. package/packages/web/components/WeeklyReports/ReportPreviewCard.tsx +187 -0
  125. package/packages/web/components/WeeklyReports/WeekCalendar.tsx +288 -0
  126. package/packages/web/components/WeeklyReports/WeeklyReports.tsx +149 -0
  127. package/packages/web/components/WeeklyReports/index.ts +4 -0
  128. package/packages/web/components/WeeklySparkline/WeeklySparkline.tsx +16 -4
  129. package/packages/web/components/WeeklySparkline/WeeklySparkline.types.ts +1 -0
  130. package/packages/web/components/charts/SessionsChart.tsx +6 -3
  131. package/packages/web/components/ui/dialog.tsx +143 -0
  132. package/packages/web/components/ui/drawer.tsx +135 -0
  133. package/packages/web/components/ui/select.tsx +187 -0
  134. package/packages/web/context/GlobalTerminalContext.tsx +538 -0
  135. package/packages/web/lib/commands.ts +81 -0
  136. package/packages/web/lib/generate-week-report.ts +285 -0
  137. package/packages/web/lib/parse-prjct-files.ts +56 -55
  138. package/packages/web/lib/project-colors.ts +58 -0
  139. package/packages/web/lib/projects.ts +58 -5
  140. package/packages/web/lib/services/projects.server.ts +11 -1
  141. package/packages/web/next-env.d.ts +1 -1
  142. package/packages/web/package.json +5 -1
  143. package/templates/commands/analyze.md +39 -3
  144. package/templates/commands/ask.md +58 -3
  145. package/templates/commands/bug.md +117 -26
  146. package/templates/commands/dash.md +95 -158
  147. package/templates/commands/done.md +130 -148
  148. package/templates/commands/feature.md +125 -103
  149. package/templates/commands/git.md +18 -3
  150. package/templates/commands/idea.md +121 -38
  151. package/templates/commands/init.md +124 -20
  152. package/templates/commands/migrate-all.md +63 -28
  153. package/templates/commands/migrate.md +140 -0
  154. package/templates/commands/next.md +115 -5
  155. package/templates/commands/now.md +146 -82
  156. package/templates/commands/pause.md +89 -74
  157. package/templates/commands/redo.md +6 -4
  158. package/templates/commands/resume.md +141 -59
  159. package/templates/commands/ship.md +103 -231
  160. package/templates/commands/spec.md +98 -8
  161. package/templates/commands/suggest.md +22 -2
  162. package/templates/commands/sync.md +192 -203
  163. package/templates/commands/undo.md +6 -4
  164. package/core/data/agents-manager.ts +0 -76
  165. package/core/data/analysis-manager.ts +0 -83
  166. package/core/data/base-manager.ts +0 -156
  167. package/core/data/ideas-manager.ts +0 -81
  168. package/core/data/outcomes-manager.ts +0 -96
  169. package/core/data/project-manager.ts +0 -75
  170. package/core/data/roadmap-manager.ts +0 -118
  171. package/core/data/shipped-manager.ts +0 -65
  172. package/core/data/state-manager.ts +0 -214
  173. package/core/state/index.ts +0 -25
  174. package/core/state/manager.ts +0 -376
  175. package/core/state/types.ts +0 -185
  176. package/core/utils/project-capabilities.ts +0 -156
  177. package/core/view-generator.ts +0 -536
  178. package/packages/web/app/project/[id]/stats/loading.tsx +0 -43
  179. package/packages/web/app/project/[id]/stats/page.tsx +0 -253
  180. package/templates/agent-assignment.md +0 -72
  181. package/templates/analysis/project-analysis.md +0 -78
  182. package/templates/checklists/accessibility.md +0 -33
  183. package/templates/commands/build.md +0 -17
  184. package/templates/commands/decision.md +0 -226
  185. package/templates/commands/fix.md +0 -79
  186. package/templates/commands/help.md +0 -61
  187. package/templates/commands/progress.md +0 -14
  188. package/templates/commands/recap.md +0 -14
  189. package/templates/commands/roadmap.md +0 -52
  190. package/templates/commands/status.md +0 -17
  191. package/templates/commands/task.md +0 -63
  192. package/templates/commands/work.md +0 -44
  193. package/templates/commands/workflow.md +0 -12
@@ -1,83 +0,0 @@
1
- /**
2
- * Analysis Manager
3
- *
4
- * Manages analysis.json - repository analysis data.
5
- */
6
-
7
- import { BaseManager } from './base-manager'
8
- import type { AnalysisSchema, CodePattern, AntiPattern } from '../schemas'
9
- import { DEFAULT_ANALYSIS } from '../schemas'
10
-
11
- class AnalysisManager extends BaseManager<AnalysisSchema> {
12
- constructor() {
13
- super('analysis.json')
14
- }
15
-
16
- protected getDefault(projectId: string): AnalysisSchema {
17
- return {
18
- ...DEFAULT_ANALYSIS,
19
- projectId,
20
- analyzedAt: new Date().toISOString()
21
- }
22
- }
23
-
24
- async getAnalysis(projectId: string): Promise<AnalysisSchema> {
25
- return this.read(projectId)
26
- }
27
-
28
- async updateAnalysis(
29
- projectId: string,
30
- updates: Partial<Omit<AnalysisSchema, 'projectId'>>
31
- ): Promise<AnalysisSchema> {
32
- return this.update(projectId, (analysis) => ({
33
- ...analysis,
34
- ...updates,
35
- analyzedAt: new Date().toISOString()
36
- }))
37
- }
38
-
39
- async setLanguages(projectId: string, languages: string[]): Promise<AnalysisSchema> {
40
- return this.updateAnalysis(projectId, { languages })
41
- }
42
-
43
- async setFrameworks(projectId: string, frameworks: string[]): Promise<AnalysisSchema> {
44
- return this.updateAnalysis(projectId, { frameworks })
45
- }
46
-
47
- async addPattern(projectId: string, pattern: CodePattern): Promise<AnalysisSchema> {
48
- return this.update(projectId, (analysis) => ({
49
- ...analysis,
50
- patterns: [...analysis.patterns, pattern],
51
- analyzedAt: new Date().toISOString()
52
- }))
53
- }
54
-
55
- async addAntiPattern(projectId: string, antiPattern: AntiPattern): Promise<AnalysisSchema> {
56
- return this.update(projectId, (analysis) => ({
57
- ...analysis,
58
- antiPatterns: [...analysis.antiPatterns, antiPattern],
59
- analyzedAt: new Date().toISOString()
60
- }))
61
- }
62
-
63
- async setPatterns(projectId: string, patterns: CodePattern[]): Promise<AnalysisSchema> {
64
- return this.updateAnalysis(projectId, { patterns })
65
- }
66
-
67
- async setAntiPatterns(projectId: string, antiPatterns: AntiPattern[]): Promise<AnalysisSchema> {
68
- return this.updateAnalysis(projectId, { antiPatterns })
69
- }
70
-
71
- async getPatterns(projectId: string): Promise<CodePattern[]> {
72
- const analysis = await this.read(projectId)
73
- return analysis.patterns
74
- }
75
-
76
- async getAntiPatterns(projectId: string): Promise<AntiPattern[]> {
77
- const analysis = await this.read(projectId)
78
- return analysis.antiPatterns
79
- }
80
- }
81
-
82
- export const analysisManager = new AnalysisManager()
83
- export default analysisManager
@@ -1,156 +0,0 @@
1
- /**
2
- * Base Manager
3
- *
4
- * Abstract base class for JSON file managers.
5
- * Provides common CRUD operations for all data types.
6
- */
7
-
8
- import path from 'path'
9
- import * as fileHelper from '../utils/file-helper'
10
- import pathManager from '../infrastructure/path-manager'
11
-
12
- export abstract class BaseManager<T> {
13
- protected filename: string
14
- protected cache: Map<string, T> = new Map()
15
- protected cacheTimeout = 5000 // 5 seconds
16
- protected lastRead: Map<string, number> = new Map()
17
-
18
- constructor(filename: string) {
19
- this.filename = filename
20
- }
21
-
22
- /**
23
- * Get file path for a project.
24
- */
25
- protected getFilePath(projectId: string): string {
26
- const globalPath = pathManager.getGlobalProjectPath(projectId)
27
- return path.join(globalPath, this.filename)
28
- }
29
-
30
- /**
31
- * Get default value for this data type.
32
- */
33
- protected abstract getDefault(projectId: string): T
34
-
35
- /**
36
- * Read data from JSON file.
37
- */
38
- async read(projectId: string): Promise<T> {
39
- const now = Date.now()
40
- const lastReadTime = this.lastRead.get(projectId) || 0
41
-
42
- // Return cached if fresh
43
- if (now - lastReadTime < this.cacheTimeout && this.cache.has(projectId)) {
44
- return this.cache.get(projectId)!
45
- }
46
-
47
- const filePath = this.getFilePath(projectId)
48
- const data = await fileHelper.readJson<T>(filePath, this.getDefault(projectId))
49
-
50
- // Update cache
51
- this.cache.set(projectId, data!)
52
- this.lastRead.set(projectId, now)
53
-
54
- return data!
55
- }
56
-
57
- /**
58
- * Write data to JSON file.
59
- */
60
- async write(projectId: string, data: T): Promise<void> {
61
- const filePath = this.getFilePath(projectId)
62
-
63
- // Ensure directory exists
64
- await fileHelper.ensureDir(path.dirname(filePath))
65
-
66
- await fileHelper.writeJson(filePath, data)
67
-
68
- // Update cache
69
- this.cache.set(projectId, data)
70
- this.lastRead.set(projectId, Date.now())
71
- }
72
-
73
- /**
74
- * Check if file exists.
75
- */
76
- async exists(projectId: string): Promise<boolean> {
77
- const filePath = this.getFilePath(projectId)
78
- return fileHelper.fileExists(filePath)
79
- }
80
-
81
- /**
82
- * Initialize with default data.
83
- */
84
- async initialize(projectId: string): Promise<T> {
85
- const data = this.getDefault(projectId)
86
- await this.write(projectId, data)
87
- return data
88
- }
89
-
90
- /**
91
- * Clear cache.
92
- */
93
- clearCache(projectId?: string): void {
94
- if (projectId) {
95
- this.cache.delete(projectId)
96
- this.lastRead.delete(projectId)
97
- } else {
98
- this.cache.clear()
99
- this.lastRead.clear()
100
- }
101
- }
102
-
103
- /**
104
- * Update data with a partial update.
105
- */
106
- async update(projectId: string, updater: (data: T) => T): Promise<T> {
107
- const current = await this.read(projectId)
108
- const updated = updater(current)
109
- await this.write(projectId, updated)
110
- return updated
111
- }
112
- }
113
-
114
- /**
115
- * Base manager for array-based JSON files.
116
- */
117
- export abstract class ArrayManager<T> extends BaseManager<T[]> {
118
- protected getDefault(): T[] {
119
- return []
120
- }
121
-
122
- /**
123
- * Add item to array.
124
- */
125
- async add(projectId: string, item: T): Promise<T[]> {
126
- return this.update(projectId, (data) => [...data, item])
127
- }
128
-
129
- /**
130
- * Remove item by predicate.
131
- */
132
- async remove(projectId: string, predicate: (item: T) => boolean): Promise<T[]> {
133
- return this.update(projectId, (data) => data.filter((item) => !predicate(item)))
134
- }
135
-
136
- /**
137
- * Find item by predicate.
138
- */
139
- async find(projectId: string, predicate: (item: T) => boolean): Promise<T | undefined> {
140
- const data = await this.read(projectId)
141
- return data.find(predicate)
142
- }
143
-
144
- /**
145
- * Update item by predicate.
146
- */
147
- async updateItem(
148
- projectId: string,
149
- predicate: (item: T) => boolean,
150
- updater: (item: T) => T
151
- ): Promise<T[]> {
152
- return this.update(projectId, (data) =>
153
- data.map((item) => (predicate(item) ? updater(item) : item))
154
- )
155
- }
156
- }
@@ -1,81 +0,0 @@
1
- /**
2
- * Ideas Manager
3
- *
4
- * Manages ideas.json - idea backlog.
5
- */
6
-
7
- import { ArrayManager } from './base-manager'
8
- import type { IdeaSchema, IdeasSchema, IdeaPriority } from '../schemas'
9
- import { DEFAULT_IDEA } from '../schemas'
10
-
11
- class IdeasManager extends ArrayManager<IdeaSchema> {
12
- constructor() {
13
- super('ideas.json')
14
- }
15
-
16
- async getIdeas(projectId: string): Promise<IdeasSchema> {
17
- return this.read(projectId)
18
- }
19
-
20
- async getPendingIdeas(projectId: string): Promise<IdeasSchema> {
21
- const ideas = await this.read(projectId)
22
- return ideas.filter((idea) => idea.status === 'pending')
23
- }
24
-
25
- async getIdea(projectId: string, id: string): Promise<IdeaSchema | undefined> {
26
- return this.find(projectId, (idea) => idea.id === id)
27
- }
28
-
29
- async addIdea(
30
- projectId: string,
31
- content: string,
32
- options?: Partial<Omit<IdeaSchema, 'id' | 'content' | 'createdAt'>>
33
- ): Promise<IdeasSchema> {
34
- const idea: IdeaSchema = {
35
- ...DEFAULT_IDEA,
36
- ...options,
37
- id: `idea_${Date.now()}`,
38
- content,
39
- createdAt: new Date().toISOString()
40
- }
41
- return this.add(projectId, idea)
42
- }
43
-
44
- async updateIdea(
45
- projectId: string,
46
- id: string,
47
- updates: Partial<Omit<IdeaSchema, 'id' | 'createdAt'>>
48
- ): Promise<IdeasSchema> {
49
- return this.updateItem(
50
- projectId,
51
- (idea) => idea.id === id,
52
- (idea) => ({ ...idea, ...updates })
53
- )
54
- }
55
-
56
- async archiveIdea(projectId: string, id: string): Promise<IdeasSchema> {
57
- return this.updateIdea(projectId, id, {
58
- status: 'archived',
59
- archivedAt: new Date().toISOString()
60
- })
61
- }
62
-
63
- async convertToFeature(projectId: string, id: string): Promise<IdeasSchema> {
64
- return this.updateIdea(projectId, id, { status: 'converted' })
65
- }
66
-
67
- async setPriority(
68
- projectId: string,
69
- id: string,
70
- priority: IdeaPriority
71
- ): Promise<IdeasSchema> {
72
- return this.updateIdea(projectId, id, { priority })
73
- }
74
-
75
- async removeIdea(projectId: string, id: string): Promise<IdeasSchema> {
76
- return this.remove(projectId, (idea) => idea.id === id)
77
- }
78
- }
79
-
80
- export const ideasManager = new IdeasManager()
81
- export default ideasManager
@@ -1,96 +0,0 @@
1
- /**
2
- * Outcomes Manager
3
- *
4
- * Manages outcomes.json - task completion metrics and history.
5
- */
6
-
7
- import { ArrayManager } from './base-manager'
8
- import type { OutcomeSchema, OutcomesSchema, QualityScore } from '../schemas'
9
-
10
- class OutcomesManager extends ArrayManager<OutcomeSchema> {
11
- constructor() {
12
- super('outcomes.json')
13
- }
14
-
15
- async getOutcomes(projectId: string): Promise<OutcomesSchema> {
16
- return this.read(projectId)
17
- }
18
-
19
- async getRecentOutcomes(projectId: string, limit = 20): Promise<OutcomesSchema> {
20
- const outcomes = await this.read(projectId)
21
- return outcomes
22
- .sort((a, b) => new Date(b.completedAt).getTime() - new Date(a.completedAt).getTime())
23
- .slice(0, limit)
24
- }
25
-
26
- async addOutcome(
27
- projectId: string,
28
- outcome: Omit<OutcomeSchema, 'id' | 'completedAt'>
29
- ): Promise<OutcomesSchema> {
30
- const fullOutcome: OutcomeSchema = {
31
- ...outcome,
32
- id: `outcome_${Date.now()}`,
33
- completedAt: new Date().toISOString()
34
- }
35
- return this.add(projectId, fullOutcome)
36
- }
37
-
38
- async getByAgent(projectId: string, agentName: string): Promise<OutcomesSchema> {
39
- const outcomes = await this.read(projectId)
40
- return outcomes.filter((o) => o.agentUsed === agentName)
41
- }
42
-
43
- async getAverageQuality(projectId: string): Promise<number> {
44
- const outcomes = await this.read(projectId)
45
- if (outcomes.length === 0) return 0
46
- const sum = outcomes.reduce((acc, o) => acc + o.qualityScore, 0)
47
- return Math.round((sum / outcomes.length) * 10) / 10
48
- }
49
-
50
- async getCompletionRate(projectId: string): Promise<number> {
51
- const outcomes = await this.read(projectId)
52
- if (outcomes.length === 0) return 0
53
- const completed = outcomes.filter((o) => o.completedAsPlanned).length
54
- return Math.round((completed / outcomes.length) * 100)
55
- }
56
-
57
- async getTopBlockers(projectId: string, limit = 5): Promise<string[]> {
58
- const outcomes = await this.read(projectId)
59
- const blockerCounts = new Map<string, number>()
60
-
61
- for (const outcome of outcomes) {
62
- for (const blocker of outcome.blockers) {
63
- blockerCounts.set(blocker, (blockerCounts.get(blocker) || 0) + 1)
64
- }
65
- }
66
-
67
- return Array.from(blockerCounts.entries())
68
- .sort((a, b) => b[1] - a[1])
69
- .slice(0, limit)
70
- .map(([blocker]) => blocker)
71
- }
72
-
73
- async getAgentStats(
74
- projectId: string,
75
- agentName: string
76
- ): Promise<{ count: number; avgQuality: number; successRate: number }> {
77
- const agentOutcomes = await this.getByAgent(projectId, agentName)
78
- if (agentOutcomes.length === 0) {
79
- return { count: 0, avgQuality: 0, successRate: 0 }
80
- }
81
-
82
- const avgQuality =
83
- agentOutcomes.reduce((acc, o) => acc + o.qualityScore, 0) / agentOutcomes.length
84
- const successRate =
85
- (agentOutcomes.filter((o) => o.completedAsPlanned).length / agentOutcomes.length) * 100
86
-
87
- return {
88
- count: agentOutcomes.length,
89
- avgQuality: Math.round(avgQuality * 10) / 10,
90
- successRate: Math.round(successRate)
91
- }
92
- }
93
- }
94
-
95
- export const outcomesManager = new OutcomesManager()
96
- export default outcomesManager
@@ -1,75 +0,0 @@
1
- /**
2
- * Project Manager
3
- *
4
- * Manages project.json - project metadata.
5
- */
6
-
7
- import { BaseManager } from './base-manager'
8
- import type { ProjectSchema } from '../schemas'
9
- import { DEFAULT_PROJECT } from '../schemas'
10
-
11
- class ProjectManager extends BaseManager<ProjectSchema> {
12
- constructor() {
13
- super('project.json')
14
- }
15
-
16
- protected getDefault(projectId: string): ProjectSchema {
17
- return {
18
- ...DEFAULT_PROJECT,
19
- projectId,
20
- name: '',
21
- repoPath: '',
22
- createdAt: new Date().toISOString(),
23
- lastSync: new Date().toISOString()
24
- }
25
- }
26
-
27
- async getProject(projectId: string): Promise<ProjectSchema> {
28
- return this.read(projectId)
29
- }
30
-
31
- async updateProject(
32
- projectId: string,
33
- updates: Partial<Omit<ProjectSchema, 'projectId'>>
34
- ): Promise<ProjectSchema> {
35
- return this.update(projectId, (project) => ({
36
- ...project,
37
- ...updates,
38
- lastSync: new Date().toISOString()
39
- }))
40
- }
41
-
42
- async setTechStack(projectId: string, techStack: string[]): Promise<ProjectSchema> {
43
- return this.updateProject(projectId, { techStack })
44
- }
45
-
46
- async setFileCount(projectId: string, fileCount: number): Promise<ProjectSchema> {
47
- return this.updateProject(projectId, { fileCount })
48
- }
49
-
50
- async setCommitCount(projectId: string, commitCount: number): Promise<ProjectSchema> {
51
- return this.updateProject(projectId, { commitCount })
52
- }
53
-
54
- async initializeProject(
55
- projectId: string,
56
- name: string,
57
- repoPath: string,
58
- options?: Partial<ProjectSchema>
59
- ): Promise<ProjectSchema> {
60
- const project: ProjectSchema = {
61
- ...DEFAULT_PROJECT,
62
- ...options,
63
- projectId,
64
- name,
65
- repoPath,
66
- createdAt: new Date().toISOString(),
67
- lastSync: new Date().toISOString()
68
- }
69
- await this.write(projectId, project)
70
- return project
71
- }
72
- }
73
-
74
- export const projectManager = new ProjectManager()
75
- export default projectManager
@@ -1,118 +0,0 @@
1
- /**
2
- * Roadmap Manager
3
- *
4
- * Manages roadmap.json - feature roadmap.
5
- */
6
-
7
- import { ArrayManager } from './base-manager'
8
- import type {
9
- FeatureSchema,
10
- RoadmapSchema,
11
- FeatureStatus,
12
- FeatureTask
13
- } from '../schemas'
14
- import { DEFAULT_FEATURE } from '../schemas'
15
-
16
- class RoadmapManager extends ArrayManager<FeatureSchema> {
17
- constructor() {
18
- super('roadmap.json')
19
- }
20
-
21
- async getFeatures(projectId: string): Promise<RoadmapSchema> {
22
- return this.read(projectId)
23
- }
24
-
25
- async getActiveFeatures(projectId: string): Promise<RoadmapSchema> {
26
- const features = await this.read(projectId)
27
- return features.filter((f) => f.status === 'in_progress')
28
- }
29
-
30
- async getFeature(projectId: string, id: string): Promise<FeatureSchema | undefined> {
31
- return this.find(projectId, (feature) => feature.id === id)
32
- }
33
-
34
- async addFeature(
35
- projectId: string,
36
- name: string,
37
- options?: Partial<Omit<FeatureSchema, 'id' | 'name' | 'createdAt'>>
38
- ): Promise<RoadmapSchema> {
39
- const feature: FeatureSchema = {
40
- ...DEFAULT_FEATURE,
41
- ...options,
42
- id: `feature_${Date.now()}`,
43
- name,
44
- createdAt: new Date().toISOString()
45
- }
46
- return this.add(projectId, feature)
47
- }
48
-
49
- async updateFeature(
50
- projectId: string,
51
- id: string,
52
- updates: Partial<Omit<FeatureSchema, 'id' | 'createdAt'>>
53
- ): Promise<RoadmapSchema> {
54
- return this.updateItem(
55
- projectId,
56
- (feature) => feature.id === id,
57
- (feature) => ({ ...feature, ...updates })
58
- )
59
- }
60
-
61
- async setStatus(
62
- projectId: string,
63
- id: string,
64
- status: FeatureStatus
65
- ): Promise<RoadmapSchema> {
66
- const updates: Partial<FeatureSchema> = { status }
67
- if (status === 'completed' || status === 'shipped') {
68
- updates.completedAt = new Date().toISOString()
69
- }
70
- return this.updateFeature(projectId, id, updates)
71
- }
72
-
73
- async addTask(
74
- projectId: string,
75
- featureId: string,
76
- task: FeatureTask
77
- ): Promise<RoadmapSchema> {
78
- return this.updateItem(
79
- projectId,
80
- (feature) => feature.id === featureId,
81
- (feature) => ({
82
- ...feature,
83
- tasks: [...feature.tasks, task]
84
- })
85
- )
86
- }
87
-
88
- async completeTask(
89
- projectId: string,
90
- featureId: string,
91
- taskIndex: number
92
- ): Promise<RoadmapSchema> {
93
- return this.updateItem(
94
- projectId,
95
- (feature) => feature.id === featureId,
96
- (feature) => ({
97
- ...feature,
98
- tasks: feature.tasks.map((task, i) =>
99
- i === taskIndex ? { ...task, completed: true } : task
100
- )
101
- })
102
- )
103
- }
104
-
105
- async removeFeature(projectId: string, id: string): Promise<RoadmapSchema> {
106
- return this.remove(projectId, (feature) => feature.id === id)
107
- }
108
-
109
- async getProgress(projectId: string, featureId: string): Promise<number> {
110
- const feature = await this.getFeature(projectId, featureId)
111
- if (!feature || feature.tasks.length === 0) return 0
112
- const completed = feature.tasks.filter((t) => t.completed).length
113
- return Math.round((completed / feature.tasks.length) * 100)
114
- }
115
- }
116
-
117
- export const roadmapManager = new RoadmapManager()
118
- export default roadmapManager
@@ -1,65 +0,0 @@
1
- /**
2
- * Shipped Manager
3
- *
4
- * Manages shipped.json - completed/shipped items history.
5
- */
6
-
7
- import { ArrayManager } from './base-manager'
8
- import type { ShippedItemSchema, ShippedSchema } from '../schemas'
9
-
10
- class ShippedManager extends ArrayManager<ShippedItemSchema> {
11
- constructor() {
12
- super('shipped.json')
13
- }
14
-
15
- async getShipped(projectId: string): Promise<ShippedSchema> {
16
- return this.read(projectId)
17
- }
18
-
19
- async getRecentShipped(projectId: string, limit = 10): Promise<ShippedSchema> {
20
- const shipped = await this.read(projectId)
21
- return shipped
22
- .sort((a, b) => new Date(b.shippedAt).getTime() - new Date(a.shippedAt).getTime())
23
- .slice(0, limit)
24
- }
25
-
26
- async addShipped(
27
- projectId: string,
28
- item: Omit<ShippedItemSchema, 'id' | 'shippedAt'>
29
- ): Promise<ShippedSchema> {
30
- const shippedItem: ShippedItemSchema = {
31
- ...item,
32
- id: `shipped_${Date.now()}`,
33
- shippedAt: new Date().toISOString()
34
- }
35
- return this.add(projectId, shippedItem)
36
- }
37
-
38
- async getByFeature(projectId: string, featureId: string): Promise<ShippedSchema> {
39
- const shipped = await this.read(projectId)
40
- return shipped.filter((item) => item.featureId === featureId)
41
- }
42
-
43
- async getTotalDuration(projectId: string): Promise<string> {
44
- const shipped = await this.read(projectId)
45
- // Parse durations and sum (simplified - assumes format like "2h 30m")
46
- let totalMinutes = 0
47
- for (const item of shipped) {
48
- const hours = item.duration.match(/(\d+)h/)
49
- const minutes = item.duration.match(/(\d+)m/)
50
- if (hours) totalMinutes += parseInt(hours[1]) * 60
51
- if (minutes) totalMinutes += parseInt(minutes[1])
52
- }
53
- const h = Math.floor(totalMinutes / 60)
54
- const m = totalMinutes % 60
55
- return h > 0 ? `${h}h ${m}m` : `${m}m`
56
- }
57
-
58
- async getCount(projectId: string): Promise<number> {
59
- const shipped = await this.read(projectId)
60
- return shipped.length
61
- }
62
- }
63
-
64
- export const shippedManager = new ShippedManager()
65
- export default shippedManager