prjct-cli 0.13.3 → 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.
- package/CHANGELOG.md +106 -0
- package/bin/prjct +10 -13
- package/core/agentic/memory-system/semantic-memories.ts +2 -1
- package/core/agentic/plan-mode/plan-mode.ts +2 -1
- package/core/agentic/prompt-builder.ts +22 -43
- package/core/agentic/services.ts +5 -5
- package/core/agentic/smart-context.ts +7 -2
- package/core/command-registry/core-commands.ts +54 -29
- package/core/command-registry/optional-commands.ts +64 -0
- package/core/command-registry/setup-commands.ts +18 -3
- package/core/commands/analysis.ts +21 -68
- package/core/commands/analytics.ts +247 -213
- package/core/commands/base.ts +1 -1
- package/core/commands/index.ts +41 -36
- package/core/commands/maintenance.ts +300 -31
- package/core/commands/planning.ts +233 -22
- package/core/commands/setup.ts +3 -8
- package/core/commands/shipping.ts +14 -18
- package/core/commands/types.ts +8 -6
- package/core/commands/workflow.ts +105 -100
- package/core/context/generator.ts +317 -0
- package/core/context-sync.ts +7 -350
- package/core/data/index.ts +13 -32
- package/core/data/md-ideas-manager.ts +155 -0
- package/core/data/md-queue-manager.ts +4 -3
- package/core/data/md-shipped-manager.ts +90 -0
- package/core/data/md-state-manager.ts +11 -7
- package/core/domain/agent-generator.ts +23 -63
- package/core/events/index.ts +143 -0
- package/core/index.ts +17 -14
- package/core/infrastructure/capability-installer.ts +13 -149
- package/core/infrastructure/migrator/project-scanner.ts +2 -1
- package/core/infrastructure/path-manager.ts +4 -6
- package/core/infrastructure/setup.ts +3 -0
- package/core/infrastructure/uuid-migration.ts +750 -0
- package/core/outcomes/recorder.ts +2 -1
- package/core/plugin/loader.ts +4 -7
- package/core/plugin/registry.ts +3 -3
- package/core/schemas/index.ts +23 -25
- package/core/schemas/state.ts +1 -0
- package/core/serializers/ideas-serializer.ts +187 -0
- package/core/serializers/index.ts +16 -0
- package/core/serializers/shipped-serializer.ts +108 -0
- package/core/session/utils.ts +3 -9
- package/core/storage/ideas-storage.ts +273 -0
- package/core/storage/index.ts +204 -0
- package/core/storage/queue-storage.ts +297 -0
- package/core/storage/shipped-storage.ts +223 -0
- package/core/storage/state-storage.ts +235 -0
- package/core/storage/storage-manager.ts +175 -0
- package/package.json +1 -1
- package/packages/web/app/api/projects/[id]/momentum/route.ts +257 -0
- package/packages/web/app/api/sessions/current/route.ts +132 -0
- package/packages/web/app/api/sessions/history/route.ts +96 -14
- package/packages/web/app/globals.css +5 -0
- package/packages/web/app/layout.tsx +2 -0
- package/packages/web/app/project/[id]/code/layout.tsx +18 -0
- package/packages/web/app/project/[id]/code/page.tsx +408 -0
- package/packages/web/app/project/[id]/page.tsx +359 -389
- package/packages/web/app/project/[id]/reports/page.tsx +59 -0
- package/packages/web/app/project/[id]/reports/print/page.tsx +58 -0
- package/packages/web/components/ActivityTimeline/ActivityTimeline.tsx +0 -1
- package/packages/web/components/AgentsCard/AgentsCard.tsx +64 -34
- package/packages/web/components/AgentsCard/AgentsCard.types.ts +1 -0
- package/packages/web/components/AppSidebar/AppSidebar.tsx +135 -11
- package/packages/web/components/BentoCard/BentoCard.constants.ts +3 -3
- package/packages/web/components/BentoCard/BentoCard.tsx +2 -1
- package/packages/web/components/BentoGrid/BentoGrid.tsx +2 -2
- package/packages/web/components/BlockersCard/BlockersCard.tsx +65 -57
- package/packages/web/components/BlockersCard/BlockersCard.types.ts +1 -0
- package/packages/web/components/CommandBar/CommandBar.tsx +67 -0
- package/packages/web/components/CommandBar/index.ts +1 -0
- package/packages/web/components/DashboardContent/DashboardContent.tsx +35 -5
- package/packages/web/components/DateGroup/DateGroup.tsx +1 -1
- package/packages/web/components/EmptyState/EmptyState.tsx +39 -21
- package/packages/web/components/EmptyState/EmptyState.types.ts +1 -0
- package/packages/web/components/EventRow/EventRow.tsx +4 -4
- package/packages/web/components/EventRow/EventRow.utils.ts +3 -3
- package/packages/web/components/HeroSection/HeroSection.tsx +52 -15
- package/packages/web/components/HeroSection/HeroSection.types.ts +4 -4
- package/packages/web/components/HeroSection/HeroSection.utils.ts +7 -3
- package/packages/web/components/IdeasCard/IdeasCard.tsx +94 -27
- package/packages/web/components/IdeasCard/IdeasCard.types.ts +1 -0
- package/packages/web/components/MasonryGrid/MasonryGrid.tsx +18 -0
- package/packages/web/components/MasonryGrid/index.ts +1 -0
- package/packages/web/components/MomentumWidget/MomentumWidget.tsx +119 -0
- package/packages/web/components/MomentumWidget/MomentumWidget.types.ts +16 -0
- package/packages/web/components/MomentumWidget/index.ts +2 -0
- package/packages/web/components/NowCard/NowCard.tsx +81 -56
- package/packages/web/components/NowCard/NowCard.types.ts +1 -0
- package/packages/web/components/PageHeader/PageHeader.tsx +24 -0
- package/packages/web/components/PageHeader/index.ts +1 -0
- package/packages/web/components/ProgressRing/ProgressRing.constants.ts +2 -2
- package/packages/web/components/ProjectAvatar/ProjectAvatar.tsx +2 -2
- package/packages/web/components/ProjectColorDot/ProjectColorDot.tsx +37 -0
- package/packages/web/components/ProjectColorDot/index.ts +1 -0
- package/packages/web/components/ProjectSelectorModal/ProjectSelectorModal.tsx +104 -0
- package/packages/web/components/ProjectSelectorModal/index.ts +1 -0
- package/packages/web/components/Providers/Providers.tsx +4 -1
- package/packages/web/components/QueueCard/QueueCard.tsx +78 -25
- package/packages/web/components/QueueCard/QueueCard.types.ts +1 -0
- package/packages/web/components/QueueCard/QueueCard.utils.ts +3 -3
- package/packages/web/components/RecoverCard/RecoverCard.tsx +72 -0
- package/packages/web/components/RecoverCard/RecoverCard.types.ts +16 -0
- package/packages/web/components/RecoverCard/index.ts +2 -0
- package/packages/web/components/RoadmapCard/RoadmapCard.tsx +101 -33
- package/packages/web/components/RoadmapCard/RoadmapCard.types.ts +1 -0
- package/packages/web/components/ShipsCard/ShipsCard.tsx +71 -28
- package/packages/web/components/ShipsCard/ShipsCard.types.ts +2 -0
- package/packages/web/components/SparklineChart/SparklineChart.tsx +20 -18
- package/packages/web/components/StatsMasonry/StatsMasonry.tsx +95 -0
- package/packages/web/components/StatsMasonry/index.ts +1 -0
- package/packages/web/components/StreakCard/StreakCard.tsx +37 -35
- package/packages/web/components/TasksCounter/TasksCounter.tsx +1 -1
- package/packages/web/components/TechStackBadges/TechStackBadges.tsx +12 -4
- package/packages/web/components/TerminalDock/DockToggleTab.tsx +29 -0
- package/packages/web/components/TerminalDock/TerminalDock.tsx +386 -0
- package/packages/web/components/TerminalDock/TerminalDockTab.tsx +130 -0
- package/packages/web/components/TerminalDock/TerminalTabBar.tsx +142 -0
- package/packages/web/components/TerminalDock/index.ts +2 -0
- package/packages/web/components/VelocityBadge/VelocityBadge.tsx +8 -3
- package/packages/web/components/VelocityCard/VelocityCard.tsx +49 -47
- package/packages/web/components/WeeklyReports/PrintableReport.tsx +259 -0
- package/packages/web/components/WeeklyReports/ReportPreviewCard.tsx +187 -0
- package/packages/web/components/WeeklyReports/WeekCalendar.tsx +288 -0
- package/packages/web/components/WeeklyReports/WeeklyReports.tsx +149 -0
- package/packages/web/components/WeeklyReports/index.ts +4 -0
- package/packages/web/components/WeeklySparkline/WeeklySparkline.tsx +16 -4
- package/packages/web/components/WeeklySparkline/WeeklySparkline.types.ts +1 -0
- package/packages/web/components/charts/SessionsChart.tsx +6 -3
- package/packages/web/components/ui/dialog.tsx +143 -0
- package/packages/web/components/ui/drawer.tsx +135 -0
- package/packages/web/components/ui/select.tsx +187 -0
- package/packages/web/context/GlobalTerminalContext.tsx +538 -0
- package/packages/web/lib/commands.ts +81 -0
- package/packages/web/lib/generate-week-report.ts +285 -0
- package/packages/web/lib/parse-prjct-files.ts +56 -55
- package/packages/web/lib/project-colors.ts +58 -0
- package/packages/web/lib/projects.ts +58 -5
- package/packages/web/lib/services/projects.server.ts +11 -1
- package/packages/web/next-env.d.ts +1 -1
- package/packages/web/package.json +5 -1
- package/templates/commands/analyze.md +39 -3
- package/templates/commands/ask.md +58 -3
- package/templates/commands/bug.md +117 -26
- package/templates/commands/dash.md +95 -158
- package/templates/commands/done.md +130 -148
- package/templates/commands/feature.md +125 -103
- package/templates/commands/git.md +18 -3
- package/templates/commands/idea.md +121 -38
- package/templates/commands/init.md +124 -20
- package/templates/commands/migrate-all.md +63 -28
- package/templates/commands/migrate.md +140 -0
- package/templates/commands/next.md +115 -5
- package/templates/commands/now.md +146 -82
- package/templates/commands/pause.md +89 -74
- package/templates/commands/redo.md +6 -4
- package/templates/commands/resume.md +141 -59
- package/templates/commands/ship.md +103 -231
- package/templates/commands/spec.md +98 -8
- package/templates/commands/suggest.md +22 -2
- package/templates/commands/sync.md +192 -203
- package/templates/commands/undo.md +6 -4
- package/core/data/agents-manager.ts +0 -76
- package/core/data/analysis-manager.ts +0 -83
- package/core/data/base-manager.ts +0 -156
- package/core/data/ideas-manager.ts +0 -81
- package/core/data/outcomes-manager.ts +0 -96
- package/core/data/project-manager.ts +0 -75
- package/core/data/roadmap-manager.ts +0 -118
- package/core/data/shipped-manager.ts +0 -65
- package/core/data/state-manager.ts +0 -214
- package/core/state/index.ts +0 -25
- package/core/state/manager.ts +0 -376
- package/core/state/types.ts +0 -185
- package/core/utils/project-capabilities.ts +0 -156
- package/core/view-generator.ts +0 -536
- package/packages/web/app/project/[id]/stats/loading.tsx +0 -43
- package/packages/web/app/project/[id]/stats/page.tsx +0 -253
- package/templates/agent-assignment.md +0 -72
- package/templates/analysis/project-analysis.md +0 -78
- package/templates/checklists/accessibility.md +0 -33
- package/templates/commands/build.md +0 -17
- package/templates/commands/decision.md +0 -226
- package/templates/commands/fix.md +0 -79
- package/templates/commands/help.md +0 -61
- package/templates/commands/progress.md +0 -14
- package/templates/commands/recap.md +0 -14
- package/templates/commands/roadmap.md +0 -52
- package/templates/commands/status.md +0 -17
- package/templates/commands/task.md +0 -63
- package/templates/commands/work.md +0 -44
- 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
|