prjct-cli 0.18.2 → 0.20.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 +82 -0
- package/CLAUDE.md +74 -211
- package/core/agentic/prompt-builder.ts +3 -7
- package/core/command-registry/optional-commands.ts +0 -20
- package/core/infrastructure/command-installer/command-installer.ts +8 -1
- package/core/infrastructure/command-installer/global-config.ts +31 -1
- package/core/infrastructure/command-installer/index.ts +1 -1
- package/core/infrastructure/setup.ts +3 -0
- package/package.json +3 -17
- package/templates/agentic/agents/uxui.md +210 -0
- package/templates/commands/bug.md +219 -41
- package/templates/commands/done.md +57 -258
- package/templates/commands/feature.md +368 -80
- package/templates/commands/now.md +72 -277
- package/templates/commands/ship.md +167 -246
- package/templates/commands/sync.md +62 -3
- package/templates/commands/test.md +160 -20
- package/templates/global/CLAUDE.md +40 -205
- package/templates/global/docs/agents.md +88 -0
- package/templates/global/docs/architecture.md +103 -0
- package/templates/global/docs/commands.md +98 -0
- package/templates/global/docs/validation.md +95 -0
- package/bin/dev.js +0 -216
- package/bin/serve.js +0 -361
- package/packages/web/README.md +0 -36
- package/packages/web/app/api/claude/sessions/route.ts +0 -44
- package/packages/web/app/api/claude/status/route.ts +0 -34
- package/packages/web/app/api/projects/[id]/icon/route.ts +0 -33
- package/packages/web/app/api/projects/[id]/momentum/route.ts +0 -257
- package/packages/web/app/api/projects/[id]/route.ts +0 -29
- package/packages/web/app/api/projects/[id]/stats/route.ts +0 -41
- package/packages/web/app/api/projects/[id]/status/route.ts +0 -21
- package/packages/web/app/api/projects/route.ts +0 -16
- package/packages/web/app/api/sessions/current/route.ts +0 -132
- package/packages/web/app/api/sessions/history/route.ts +0 -204
- package/packages/web/app/error.tsx +0 -34
- package/packages/web/app/favicon.ico +0 -0
- package/packages/web/app/globals.css +0 -198
- package/packages/web/app/layout.tsx +0 -53
- package/packages/web/app/loading.tsx +0 -7
- package/packages/web/app/not-found.tsx +0 -25
- package/packages/web/app/page.tsx +0 -12
- package/packages/web/app/project/[id]/code/layout.tsx +0 -18
- package/packages/web/app/project/[id]/code/page.tsx +0 -408
- package/packages/web/app/project/[id]/error.tsx +0 -41
- package/packages/web/app/project/[id]/loading.tsx +0 -9
- package/packages/web/app/project/[id]/not-found.tsx +0 -27
- package/packages/web/app/project/[id]/page.tsx +0 -384
- package/packages/web/app/project/[id]/reports/page.tsx +0 -59
- package/packages/web/app/project/[id]/reports/print/page.tsx +0 -58
- package/packages/web/app/sessions/page.tsx +0 -165
- package/packages/web/app/settings/page.tsx +0 -151
- package/packages/web/components/ActivityTimeline/ActivityTimeline.constants.ts +0 -2
- package/packages/web/components/ActivityTimeline/ActivityTimeline.tsx +0 -49
- package/packages/web/components/ActivityTimeline/ActivityTimeline.types.ts +0 -8
- package/packages/web/components/ActivityTimeline/hooks/index.ts +0 -2
- package/packages/web/components/ActivityTimeline/hooks/useExpandable.ts +0 -9
- package/packages/web/components/ActivityTimeline/hooks/useGroupedEvents.ts +0 -23
- package/packages/web/components/ActivityTimeline/index.ts +0 -2
- package/packages/web/components/AgentsCard/AgentsCard.tsx +0 -93
- package/packages/web/components/AgentsCard/AgentsCard.types.ts +0 -14
- package/packages/web/components/AgentsCard/index.ts +0 -2
- package/packages/web/components/AppSidebar/AppSidebar.tsx +0 -316
- package/packages/web/components/AppSidebar/index.ts +0 -1
- package/packages/web/components/BackLink/BackLink.tsx +0 -18
- package/packages/web/components/BackLink/BackLink.types.ts +0 -5
- package/packages/web/components/BackLink/index.ts +0 -2
- package/packages/web/components/BentoCard/BentoCard.constants.ts +0 -16
- package/packages/web/components/BentoCard/BentoCard.tsx +0 -48
- package/packages/web/components/BentoCard/BentoCard.types.ts +0 -15
- package/packages/web/components/BentoCard/index.ts +0 -2
- package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.constants.ts +0 -9
- package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.tsx +0 -18
- package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.types.ts +0 -5
- package/packages/web/components/BentoCardSkeleton/index.ts +0 -2
- package/packages/web/components/BentoGrid/BentoGrid.tsx +0 -18
- package/packages/web/components/BentoGrid/BentoGrid.types.ts +0 -4
- package/packages/web/components/BentoGrid/index.ts +0 -2
- package/packages/web/components/BlockersCard/BlockersCard.tsx +0 -75
- package/packages/web/components/BlockersCard/BlockersCard.types.ts +0 -12
- package/packages/web/components/BlockersCard/index.ts +0 -2
- package/packages/web/components/CommandBar/CommandBar.tsx +0 -67
- package/packages/web/components/CommandBar/index.ts +0 -1
- package/packages/web/components/CommandButton/CommandButton.tsx +0 -46
- package/packages/web/components/CommandButton/index.ts +0 -1
- package/packages/web/components/ConnectionStatus/ConnectionStatus.tsx +0 -29
- package/packages/web/components/ConnectionStatus/index.ts +0 -1
- package/packages/web/components/DashboardContent/DashboardContent.tsx +0 -284
- package/packages/web/components/DashboardContent/index.ts +0 -1
- package/packages/web/components/DateGroup/DateGroup.tsx +0 -18
- package/packages/web/components/DateGroup/DateGroup.types.ts +0 -6
- package/packages/web/components/DateGroup/DateGroup.utils.ts +0 -11
- package/packages/web/components/DateGroup/index.ts +0 -2
- package/packages/web/components/EmptyState/EmptyState.tsx +0 -76
- package/packages/web/components/EmptyState/EmptyState.types.ts +0 -11
- package/packages/web/components/EmptyState/index.ts +0 -2
- package/packages/web/components/EventRow/EventRow.constants.ts +0 -10
- package/packages/web/components/EventRow/EventRow.tsx +0 -49
- package/packages/web/components/EventRow/EventRow.types.ts +0 -7
- package/packages/web/components/EventRow/EventRow.utils.ts +0 -49
- package/packages/web/components/EventRow/index.ts +0 -2
- package/packages/web/components/ExpandButton/ExpandButton.tsx +0 -18
- package/packages/web/components/ExpandButton/ExpandButton.types.ts +0 -6
- package/packages/web/components/ExpandButton/index.ts +0 -2
- package/packages/web/components/HealthGradientBackground/HealthGradientBackground.tsx +0 -14
- package/packages/web/components/HealthGradientBackground/HealthGradientBackground.types.ts +0 -5
- package/packages/web/components/HealthGradientBackground/HealthGradientBackground.utils.ts +0 -13
- package/packages/web/components/HealthGradientBackground/index.ts +0 -2
- package/packages/web/components/HeroSection/HeroSection.tsx +0 -92
- package/packages/web/components/HeroSection/HeroSection.types.ts +0 -14
- package/packages/web/components/HeroSection/HeroSection.utils.ts +0 -11
- package/packages/web/components/HeroSection/hooks/index.ts +0 -2
- package/packages/web/components/HeroSection/hooks/useCountUp.ts +0 -45
- package/packages/web/components/HeroSection/hooks/useWeeklyActivity.ts +0 -18
- package/packages/web/components/HeroSection/index.ts +0 -2
- package/packages/web/components/IdeasCard/IdeasCard.tsx +0 -115
- package/packages/web/components/IdeasCard/IdeasCard.types.ts +0 -10
- package/packages/web/components/IdeasCard/index.ts +0 -2
- package/packages/web/components/InsightMessage/InsightMessage.tsx +0 -9
- package/packages/web/components/InsightMessage/InsightMessage.types.ts +0 -3
- package/packages/web/components/InsightMessage/index.ts +0 -2
- package/packages/web/components/Logo/Logo.tsx +0 -65
- package/packages/web/components/Logo/index.ts +0 -1
- package/packages/web/components/MarkdownContent/MarkdownContent.tsx +0 -123
- package/packages/web/components/MarkdownContent/index.ts +0 -1
- package/packages/web/components/MasonryGrid/MasonryGrid.tsx +0 -18
- package/packages/web/components/MasonryGrid/index.ts +0 -1
- package/packages/web/components/MomentumWidget/MomentumWidget.tsx +0 -119
- package/packages/web/components/MomentumWidget/MomentumWidget.types.ts +0 -16
- package/packages/web/components/MomentumWidget/index.ts +0 -2
- package/packages/web/components/NowCard/NowCard.tsx +0 -118
- package/packages/web/components/NowCard/NowCard.types.ts +0 -16
- package/packages/web/components/NowCard/index.ts +0 -2
- package/packages/web/components/PageHeader/PageHeader.tsx +0 -24
- package/packages/web/components/PageHeader/index.ts +0 -1
- package/packages/web/components/ProgressRing/ProgressRing.constants.ts +0 -20
- package/packages/web/components/ProgressRing/ProgressRing.tsx +0 -51
- package/packages/web/components/ProgressRing/ProgressRing.types.ts +0 -11
- package/packages/web/components/ProgressRing/index.ts +0 -2
- package/packages/web/components/ProjectAvatar/ProjectAvatar.tsx +0 -54
- package/packages/web/components/ProjectAvatar/index.ts +0 -1
- package/packages/web/components/ProjectColorDot/ProjectColorDot.tsx +0 -37
- package/packages/web/components/ProjectColorDot/index.ts +0 -1
- package/packages/web/components/ProjectSelectorModal/ProjectSelectorModal.tsx +0 -104
- package/packages/web/components/ProjectSelectorModal/index.ts +0 -1
- package/packages/web/components/Providers/Providers.tsx +0 -48
- package/packages/web/components/Providers/index.ts +0 -1
- package/packages/web/components/QueueCard/QueueCard.tsx +0 -125
- package/packages/web/components/QueueCard/QueueCard.types.ts +0 -12
- package/packages/web/components/QueueCard/QueueCard.utils.ts +0 -12
- package/packages/web/components/QueueCard/index.ts +0 -2
- package/packages/web/components/RecoverCard/RecoverCard.tsx +0 -72
- package/packages/web/components/RecoverCard/RecoverCard.types.ts +0 -16
- package/packages/web/components/RecoverCard/index.ts +0 -2
- package/packages/web/components/RoadmapCard/RoadmapCard.tsx +0 -145
- package/packages/web/components/RoadmapCard/RoadmapCard.types.ts +0 -16
- package/packages/web/components/RoadmapCard/index.ts +0 -2
- package/packages/web/components/ShipsCard/ShipsCard.tsx +0 -95
- package/packages/web/components/ShipsCard/ShipsCard.types.ts +0 -14
- package/packages/web/components/ShipsCard/ShipsCard.utils.ts +0 -4
- package/packages/web/components/ShipsCard/index.ts +0 -2
- package/packages/web/components/SparklineChart/SparklineChart.tsx +0 -40
- package/packages/web/components/SparklineChart/SparklineChart.types.ts +0 -6
- package/packages/web/components/SparklineChart/index.ts +0 -2
- package/packages/web/components/StatsMasonry/StatsMasonry.tsx +0 -95
- package/packages/web/components/StatsMasonry/index.ts +0 -1
- package/packages/web/components/StreakCard/StreakCard.constants.ts +0 -2
- package/packages/web/components/StreakCard/StreakCard.tsx +0 -55
- package/packages/web/components/StreakCard/StreakCard.types.ts +0 -4
- package/packages/web/components/StreakCard/index.ts +0 -2
- package/packages/web/components/TasksCounter/TasksCounter.tsx +0 -14
- package/packages/web/components/TasksCounter/TasksCounter.types.ts +0 -3
- package/packages/web/components/TasksCounter/index.ts +0 -2
- package/packages/web/components/TechStackBadges/TechStackBadges.tsx +0 -28
- package/packages/web/components/TechStackBadges/index.ts +0 -1
- package/packages/web/components/TerminalDock/DockToggleTab.tsx +0 -29
- package/packages/web/components/TerminalDock/TerminalDock.tsx +0 -386
- package/packages/web/components/TerminalDock/TerminalDockTab.tsx +0 -130
- package/packages/web/components/TerminalDock/TerminalTabBar.tsx +0 -142
- package/packages/web/components/TerminalDock/index.ts +0 -2
- package/packages/web/components/TerminalTabs/TerminalTab.tsx +0 -95
- package/packages/web/components/TerminalTabs/TerminalTabs.tsx +0 -211
- package/packages/web/components/TerminalTabs/index.ts +0 -1
- package/packages/web/components/VelocityBadge/VelocityBadge.tsx +0 -32
- package/packages/web/components/VelocityBadge/VelocityBadge.types.ts +0 -3
- package/packages/web/components/VelocityBadge/index.ts +0 -2
- package/packages/web/components/VelocityCard/VelocityCard.tsx +0 -73
- package/packages/web/components/VelocityCard/VelocityCard.types.ts +0 -7
- package/packages/web/components/VelocityCard/index.ts +0 -2
- package/packages/web/components/WeeklyReports/PrintableReport.tsx +0 -259
- package/packages/web/components/WeeklyReports/ReportPreviewCard.tsx +0 -187
- package/packages/web/components/WeeklyReports/WeekCalendar.tsx +0 -288
- package/packages/web/components/WeeklyReports/WeeklyReports.tsx +0 -149
- package/packages/web/components/WeeklyReports/index.ts +0 -4
- package/packages/web/components/WeeklySparkline/WeeklySparkline.tsx +0 -25
- package/packages/web/components/WeeklySparkline/WeeklySparkline.types.ts +0 -4
- package/packages/web/components/WeeklySparkline/index.ts +0 -2
- package/packages/web/components/charts/SessionsChart.tsx +0 -175
- package/packages/web/components/ui/alert-dialog.tsx +0 -157
- package/packages/web/components/ui/badge.tsx +0 -46
- package/packages/web/components/ui/button.tsx +0 -60
- package/packages/web/components/ui/card.tsx +0 -92
- package/packages/web/components/ui/chart.tsx +0 -385
- package/packages/web/components/ui/dialog.tsx +0 -143
- package/packages/web/components/ui/drawer.tsx +0 -135
- package/packages/web/components/ui/dropdown-menu.tsx +0 -257
- package/packages/web/components/ui/input.tsx +0 -21
- package/packages/web/components/ui/scroll-area.tsx +0 -58
- package/packages/web/components/ui/select.tsx +0 -187
- package/packages/web/components/ui/sheet.tsx +0 -139
- package/packages/web/components/ui/tabs.tsx +0 -66
- package/packages/web/components/ui/tooltip.tsx +0 -61
- package/packages/web/components.json +0 -22
- package/packages/web/context/GlobalTerminalContext.tsx +0 -538
- package/packages/web/context/TerminalContext.tsx +0 -45
- package/packages/web/context/TerminalTabsContext.tsx +0 -181
- package/packages/web/eslint.config.mjs +0 -18
- package/packages/web/hooks/useClaudeTerminal.ts +0 -425
- package/packages/web/hooks/useProjectStats.ts +0 -93
- package/packages/web/hooks/useProjects.ts +0 -73
- package/packages/web/lib/actions/projects.ts +0 -15
- package/packages/web/lib/commands.ts +0 -81
- package/packages/web/lib/format.ts +0 -23
- package/packages/web/lib/generate-week-report.ts +0 -285
- package/packages/web/lib/parse-prjct-files.ts +0 -1123
- package/packages/web/lib/project-colors.ts +0 -58
- package/packages/web/lib/projects.ts +0 -506
- package/packages/web/lib/pty.ts +0 -101
- package/packages/web/lib/query-config.ts +0 -44
- package/packages/web/lib/services/index.ts +0 -9
- package/packages/web/lib/services/projects.server.ts +0 -66
- package/packages/web/lib/services/stats.server.ts +0 -562
- package/packages/web/lib/unified-loader.ts +0 -396
- package/packages/web/lib/utils.ts +0 -6
- package/packages/web/next-env.d.ts +0 -6
- package/packages/web/next.config.ts +0 -7
- package/packages/web/package.json +0 -57
- package/packages/web/postcss.config.mjs +0 -7
- package/packages/web/public/file.svg +0 -1
- package/packages/web/public/globe.svg +0 -1
- package/packages/web/public/next.svg +0 -1
- package/packages/web/public/vercel.svg +0 -1
- package/packages/web/public/window.svg +0 -1
- package/packages/web/server.ts +0 -312
- package/packages/web/tsconfig.json +0 -34
- package/templates/commands/serve.md +0 -121
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useQuery } from '@tanstack/react-query'
|
|
4
|
-
import type { ProjectStats, RawProjectFiles } from '@/lib/parse-prjct-files'
|
|
5
|
-
import type {
|
|
6
|
-
UnifiedApiResponse,
|
|
7
|
-
ProjectState,
|
|
8
|
-
OutcomeSummary,
|
|
9
|
-
AgentPerformance,
|
|
10
|
-
ProjectInsights,
|
|
11
|
-
} from '@prjct/shared'
|
|
12
|
-
|
|
13
|
-
interface ProjectStatsResponse {
|
|
14
|
-
success: boolean
|
|
15
|
-
data?: ProjectStats
|
|
16
|
-
raw?: RawProjectFiles
|
|
17
|
-
error?: string
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
interface ProjectStatsData {
|
|
21
|
-
stats: ProjectStats
|
|
22
|
-
raw: RawProjectFiles
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Legacy fetch
|
|
26
|
-
async function fetchProjectStats(projectId: string): Promise<ProjectStatsData> {
|
|
27
|
-
const res = await fetch(`/api/projects/${projectId}/stats`, {
|
|
28
|
-
cache: 'no-store',
|
|
29
|
-
})
|
|
30
|
-
if (!res.ok) throw new Error('Failed to fetch project stats')
|
|
31
|
-
const json: ProjectStatsResponse = await res.json()
|
|
32
|
-
if (!json.success || !json.data || !json.raw) {
|
|
33
|
-
throw new Error(json.error || 'Failed to fetch project stats')
|
|
34
|
-
}
|
|
35
|
-
return { stats: json.data, raw: json.raw }
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function useProjectStats(projectId: string) {
|
|
39
|
-
return useQuery({
|
|
40
|
-
queryKey: ['project-stats', projectId],
|
|
41
|
-
queryFn: () => fetchProjectStats(projectId),
|
|
42
|
-
staleTime: 30_000, // Cache 30s
|
|
43
|
-
refetchOnWindowFocus: true,
|
|
44
|
-
enabled: !!projectId,
|
|
45
|
-
})
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// ============== Unified API ==============
|
|
49
|
-
|
|
50
|
-
interface UnifiedProjectData {
|
|
51
|
-
state: ProjectState | null
|
|
52
|
-
outcomes: OutcomeSummary | null
|
|
53
|
-
agentPerformance: AgentPerformance[]
|
|
54
|
-
insights: ProjectInsights
|
|
55
|
-
legacyFallback: boolean
|
|
56
|
-
// Legacy data when fallback
|
|
57
|
-
legacyData?: ProjectStats
|
|
58
|
-
legacyRaw?: RawProjectFiles
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async function fetchUnifiedProjectData(projectId: string): Promise<UnifiedProjectData> {
|
|
62
|
-
const res = await fetch(`/api/v2/projects/${projectId}/unified`, {
|
|
63
|
-
cache: 'no-store',
|
|
64
|
-
})
|
|
65
|
-
if (!res.ok) throw new Error('Failed to fetch unified project data')
|
|
66
|
-
const json: UnifiedApiResponse = await res.json()
|
|
67
|
-
if (!json.success) {
|
|
68
|
-
throw new Error('Failed to fetch unified project data')
|
|
69
|
-
}
|
|
70
|
-
return {
|
|
71
|
-
state: json.state,
|
|
72
|
-
outcomes: json.outcomes,
|
|
73
|
-
agentPerformance: json.agentPerformance,
|
|
74
|
-
insights: json.insights,
|
|
75
|
-
legacyFallback: json.legacyFallback,
|
|
76
|
-
legacyData: json.legacyData as ProjectStats | undefined,
|
|
77
|
-
legacyRaw: json.legacyRaw as RawProjectFiles | undefined,
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Hook for fetching unified project data from v2 API.
|
|
83
|
-
* Falls back to legacy data if unified state doesn't exist.
|
|
84
|
-
*/
|
|
85
|
-
export function useUnifiedProjectStats(projectId: string) {
|
|
86
|
-
return useQuery({
|
|
87
|
-
queryKey: ['project-unified', projectId],
|
|
88
|
-
queryFn: () => fetchUnifiedProjectData(projectId),
|
|
89
|
-
staleTime: 30_000, // Cache 30s
|
|
90
|
-
refetchOnWindowFocus: true,
|
|
91
|
-
enabled: !!projectId,
|
|
92
|
-
})
|
|
93
|
-
}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
|
4
|
-
import { queryPresets } from '@/lib/query-config'
|
|
5
|
-
import { deleteProject as deleteProjectAction } from '@/lib/actions/projects'
|
|
6
|
-
|
|
7
|
-
export interface Project {
|
|
8
|
-
id: string
|
|
9
|
-
name: string
|
|
10
|
-
path: string
|
|
11
|
-
repoPath?: string | null
|
|
12
|
-
currentTask?: string | null
|
|
13
|
-
hasActiveSession?: boolean
|
|
14
|
-
lastActivity?: string | null
|
|
15
|
-
ideasCount?: number
|
|
16
|
-
nextTasksCount?: number
|
|
17
|
-
techStack?: string[]
|
|
18
|
-
iconPath?: string | null
|
|
19
|
-
version?: string
|
|
20
|
-
stack?: string
|
|
21
|
-
filesCount?: number
|
|
22
|
-
commitsCount?: number
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Fetch with no-cache headers for fresh data
|
|
26
|
-
async function fetchJson<T>(url: string): Promise<T> {
|
|
27
|
-
const res = await fetch(url, {
|
|
28
|
-
cache: 'no-store',
|
|
29
|
-
headers: {
|
|
30
|
-
'Cache-Control': 'no-cache',
|
|
31
|
-
},
|
|
32
|
-
})
|
|
33
|
-
if (!res.ok) throw new Error(`Failed to fetch ${url}`)
|
|
34
|
-
const json = await res.json()
|
|
35
|
-
return json.data ?? json
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Hook for fetching all projects
|
|
39
|
-
export function useProjects() {
|
|
40
|
-
return useQuery({
|
|
41
|
-
queryKey: ['projects'],
|
|
42
|
-
queryFn: () => fetchJson<Project[]>('/api/projects'),
|
|
43
|
-
...queryPresets.normal,
|
|
44
|
-
})
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Hook for fetching a single project
|
|
48
|
-
export function useProject(projectId: string | null) {
|
|
49
|
-
return useQuery({
|
|
50
|
-
queryKey: ['project', projectId],
|
|
51
|
-
queryFn: () => fetchJson<Project>(`/api/projects/${projectId}`),
|
|
52
|
-
enabled: !!projectId,
|
|
53
|
-
...queryPresets.fast,
|
|
54
|
-
})
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Hook for deleting a project (uses Server Action)
|
|
58
|
-
export function useDeleteProject() {
|
|
59
|
-
const queryClient = useQueryClient()
|
|
60
|
-
|
|
61
|
-
return useMutation({
|
|
62
|
-
mutationFn: async (projectId: string) => {
|
|
63
|
-
const result = await deleteProjectAction(projectId)
|
|
64
|
-
if (!result.success) {
|
|
65
|
-
throw new Error(result.error || 'Failed to delete project')
|
|
66
|
-
}
|
|
67
|
-
return result
|
|
68
|
-
},
|
|
69
|
-
onSuccess: () => {
|
|
70
|
-
queryClient.invalidateQueries({ queryKey: ['projects'] })
|
|
71
|
-
},
|
|
72
|
-
})
|
|
73
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
'use server'
|
|
2
|
-
|
|
3
|
-
import { revalidatePath } from 'next/cache'
|
|
4
|
-
import { moveToTrash } from '@/lib/projects'
|
|
5
|
-
|
|
6
|
-
export async function deleteProject(projectId: string) {
|
|
7
|
-
try {
|
|
8
|
-
const result = await moveToTrash(projectId)
|
|
9
|
-
revalidatePath('/')
|
|
10
|
-
return { success: true, ...result }
|
|
11
|
-
} catch (error) {
|
|
12
|
-
const message = error instanceof Error ? error.message : 'Failed to delete project'
|
|
13
|
-
return { success: false, error: message }
|
|
14
|
-
}
|
|
15
|
-
}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Play,
|
|
3
|
-
Target,
|
|
4
|
-
Lightbulb,
|
|
5
|
-
ListTodo,
|
|
6
|
-
Rocket,
|
|
7
|
-
Sparkles,
|
|
8
|
-
CheckCircle2,
|
|
9
|
-
Pause,
|
|
10
|
-
BarChart3,
|
|
11
|
-
TrendingUp,
|
|
12
|
-
Activity,
|
|
13
|
-
History,
|
|
14
|
-
Undo2,
|
|
15
|
-
Redo2,
|
|
16
|
-
RefreshCw,
|
|
17
|
-
type LucideIcon,
|
|
18
|
-
} from 'lucide-react'
|
|
19
|
-
|
|
20
|
-
export interface WorkflowCommand {
|
|
21
|
-
cmd: string
|
|
22
|
-
icon: LucideIcon
|
|
23
|
-
tip: string
|
|
24
|
-
group: CommandGroup
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export type CommandGroup = 'work' | 'session' | 'plan' | 'ship' | 'status' | 'recovery'
|
|
28
|
-
|
|
29
|
-
// Commands ordered by real developer workflow
|
|
30
|
-
export const WORKFLOW_COMMANDS: readonly WorkflowCommand[] = [
|
|
31
|
-
{ cmd: 'p. now', icon: Target, tip: 'Set task', group: 'work' },
|
|
32
|
-
{ cmd: 'p. done', icon: CheckCircle2, tip: 'Complete', group: 'work' },
|
|
33
|
-
{ cmd: 'p. pause', icon: Pause, tip: 'Pause', group: 'session' },
|
|
34
|
-
{ cmd: 'p. resume', icon: Play, tip: 'Resume', group: 'session' },
|
|
35
|
-
{ cmd: 'p. feature', icon: Sparkles, tip: 'Feature', group: 'plan' },
|
|
36
|
-
{ cmd: 'p. idea', icon: Lightbulb, tip: 'Idea', group: 'plan' },
|
|
37
|
-
{ cmd: 'p. next', icon: ListTodo, tip: 'Queue', group: 'plan' },
|
|
38
|
-
{ cmd: 'p. ship', icon: Rocket, tip: 'Ship', group: 'ship' },
|
|
39
|
-
{ cmd: 'p. recap', icon: BarChart3, tip: 'Recap', group: 'status' },
|
|
40
|
-
{ cmd: 'p. progress', icon: TrendingUp, tip: 'Progress', group: 'status' },
|
|
41
|
-
{ cmd: 'p. status', icon: Activity, tip: 'Status', group: 'status' },
|
|
42
|
-
{ cmd: 'p. history', icon: History, tip: 'History', group: 'status' },
|
|
43
|
-
{ cmd: 'p. undo', icon: Undo2, tip: 'Undo', group: 'recovery' },
|
|
44
|
-
{ cmd: 'p. redo', icon: Redo2, tip: 'Redo', group: 'recovery' },
|
|
45
|
-
] as const
|
|
46
|
-
|
|
47
|
-
export const COMMAND_GROUPS: readonly CommandGroup[] = ['work', 'session', 'plan', 'ship', 'status', 'recovery']
|
|
48
|
-
|
|
49
|
-
// Sync command - always first/prominent
|
|
50
|
-
export const SYNC_COMMAND: WorkflowCommand = {
|
|
51
|
-
cmd: 'p. sync',
|
|
52
|
-
icon: RefreshCw,
|
|
53
|
-
tip: 'Sync',
|
|
54
|
-
group: 'status',
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Get commands by group
|
|
58
|
-
export function getCommandsByGroup(group: CommandGroup): WorkflowCommand[] {
|
|
59
|
-
return WORKFLOW_COMMANDS.filter(c => c.group === group)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Project colors for tabs (based on project ID hash)
|
|
63
|
-
export const PROJECT_COLORS = [
|
|
64
|
-
'bg-orange-500/20 border-orange-500/50 text-orange-400',
|
|
65
|
-
'bg-blue-500/20 border-blue-500/50 text-blue-400',
|
|
66
|
-
'bg-green-500/20 border-green-500/50 text-green-400',
|
|
67
|
-
'bg-purple-500/20 border-purple-500/50 text-purple-400',
|
|
68
|
-
'bg-pink-500/20 border-pink-500/50 text-pink-400',
|
|
69
|
-
'bg-cyan-500/20 border-cyan-500/50 text-cyan-400',
|
|
70
|
-
'bg-yellow-500/20 border-yellow-500/50 text-yellow-400',
|
|
71
|
-
'bg-red-500/20 border-red-500/50 text-red-400',
|
|
72
|
-
]
|
|
73
|
-
|
|
74
|
-
export function getProjectColor(projectId: string): string {
|
|
75
|
-
let hash = 0
|
|
76
|
-
for (let i = 0; i < projectId.length; i++) {
|
|
77
|
-
hash = ((hash << 5) - hash) + projectId.charCodeAt(i)
|
|
78
|
-
hash = hash & hash
|
|
79
|
-
}
|
|
80
|
-
return PROJECT_COLORS[Math.abs(hash) % PROJECT_COLORS.length]
|
|
81
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared formatting utilities
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export function formatRelativeTime(dateStr: string | null | undefined): string {
|
|
6
|
-
if (!dateStr) return ''
|
|
7
|
-
const date = new Date(dateStr)
|
|
8
|
-
const now = new Date()
|
|
9
|
-
const diffMs = now.getTime() - date.getTime()
|
|
10
|
-
const diffMins = Math.floor(diffMs / 60000)
|
|
11
|
-
const diffHours = Math.floor(diffMs / 3600000)
|
|
12
|
-
const diffDays = Math.floor(diffMs / 86400000)
|
|
13
|
-
|
|
14
|
-
if (diffMins < 1) return 'just now'
|
|
15
|
-
if (diffMins < 60) return `${diffMins}m ago`
|
|
16
|
-
if (diffHours < 24) return `${diffHours}h ago`
|
|
17
|
-
if (diffDays < 7) return `${diffDays}d ago`
|
|
18
|
-
return date.toLocaleDateString()
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function formatPath(path: string): string {
|
|
22
|
-
return path.replace(/^\/Users\/[^/]+\//, '~/')
|
|
23
|
-
}
|
|
@@ -1,285 +0,0 @@
|
|
|
1
|
-
import type { StatsResult } from './services/stats.server'
|
|
2
|
-
|
|
3
|
-
export interface ShippedItem {
|
|
4
|
-
name: string
|
|
5
|
-
date: string
|
|
6
|
-
version?: string
|
|
7
|
-
type?: string
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface WeekData {
|
|
11
|
-
year: number
|
|
12
|
-
week: number
|
|
13
|
-
startDate: Date
|
|
14
|
-
endDate: Date
|
|
15
|
-
shipped: ShippedItem[]
|
|
16
|
-
tasksCompleted: number
|
|
17
|
-
bugsFixed: number
|
|
18
|
-
syncs: number
|
|
19
|
-
activeDays: number
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Get ISO week number for a date
|
|
24
|
-
*/
|
|
25
|
-
export function getWeekNumber(date: Date): number {
|
|
26
|
-
const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()))
|
|
27
|
-
const dayNum = d.getUTCDay() || 7
|
|
28
|
-
d.setUTCDate(d.getUTCDate() + 4 - dayNum)
|
|
29
|
-
const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1))
|
|
30
|
-
return Math.ceil((((d.getTime() - yearStart.getTime()) / 86400000) + 1) / 7)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Get current year and week
|
|
35
|
-
*/
|
|
36
|
-
export function getCurrentYearWeek(): { year: number; week: number } {
|
|
37
|
-
const now = new Date()
|
|
38
|
-
return {
|
|
39
|
-
year: now.getFullYear(),
|
|
40
|
-
week: getWeekNumber(now)
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Get start and end dates for a given ISO week
|
|
46
|
-
*/
|
|
47
|
-
export function getWeekDateRange(year: number, week: number): { start: Date; end: Date } {
|
|
48
|
-
// Find January 4th of the year (always in week 1)
|
|
49
|
-
const jan4 = new Date(year, 0, 4)
|
|
50
|
-
const dayOfWeek = jan4.getDay() || 7
|
|
51
|
-
|
|
52
|
-
// Find Monday of week 1
|
|
53
|
-
const week1Monday = new Date(jan4)
|
|
54
|
-
week1Monday.setDate(jan4.getDate() - dayOfWeek + 1)
|
|
55
|
-
|
|
56
|
-
// Calculate target week's Monday
|
|
57
|
-
const targetMonday = new Date(week1Monday)
|
|
58
|
-
targetMonday.setDate(week1Monday.getDate() + (week - 1) * 7)
|
|
59
|
-
|
|
60
|
-
// Calculate Sunday
|
|
61
|
-
const targetSunday = new Date(targetMonday)
|
|
62
|
-
targetSunday.setDate(targetMonday.getDate() + 6)
|
|
63
|
-
|
|
64
|
-
return { start: targetMonday, end: targetSunday }
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Format date range as string
|
|
69
|
-
*/
|
|
70
|
-
export function formatDateRange(start: Date, end: Date): string {
|
|
71
|
-
const startMonth = start.toLocaleDateString('en-US', { month: 'short' })
|
|
72
|
-
const endMonth = end.toLocaleDateString('en-US', { month: 'short' })
|
|
73
|
-
|
|
74
|
-
if (startMonth === endMonth) {
|
|
75
|
-
return `${startMonth} ${start.getDate()}-${end.getDate()}`
|
|
76
|
-
}
|
|
77
|
-
return `${startMonth} ${start.getDate()} - ${endMonth} ${end.getDate()}`
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Check if a date falls within a week
|
|
82
|
-
*/
|
|
83
|
-
function isDateInWeek(dateStr: string, weekStart: Date, weekEnd: Date): boolean {
|
|
84
|
-
const date = new Date(dateStr)
|
|
85
|
-
return date >= weekStart && date <= weekEnd
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Filter stats data by week
|
|
90
|
-
*/
|
|
91
|
-
export function filterDataByWeek(
|
|
92
|
-
stats: StatsResult,
|
|
93
|
-
year: number,
|
|
94
|
-
week: number
|
|
95
|
-
): WeekData {
|
|
96
|
-
const { start, end } = getWeekDateRange(year, week)
|
|
97
|
-
|
|
98
|
-
// 1. Shipped features from legacyStats.shipped (parsed from shipped.md)
|
|
99
|
-
const shipped: ShippedItem[] = (stats.legacyStats?.shipped ?? [])
|
|
100
|
-
.filter(item => {
|
|
101
|
-
if (!item.date) return false
|
|
102
|
-
return isDateInWeek(item.date, start, end)
|
|
103
|
-
})
|
|
104
|
-
.map(item => ({
|
|
105
|
-
name: item.name,
|
|
106
|
-
date: item.date!,
|
|
107
|
-
version: item.version,
|
|
108
|
-
type: item.type
|
|
109
|
-
}))
|
|
110
|
-
|
|
111
|
-
// 2. Timeline events from legacyStats.timeline (parsed from context.jsonl)
|
|
112
|
-
const timeline = stats.legacyStats?.timeline ?? []
|
|
113
|
-
const weekEvents = timeline.filter(e => {
|
|
114
|
-
if (!e.ts) return false
|
|
115
|
-
return isDateInWeek(e.ts, start, end)
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
// Count tasks completed
|
|
119
|
-
const tasksCompleted = weekEvents.filter(e =>
|
|
120
|
-
e.type === 'task_complete' ||
|
|
121
|
-
e.type === 'task_completed' ||
|
|
122
|
-
e.type === 'session_completed'
|
|
123
|
-
).length
|
|
124
|
-
|
|
125
|
-
// Count bugs fixed
|
|
126
|
-
const bugsFixed = weekEvents.filter(e =>
|
|
127
|
-
e.type === 'bug_fix' ||
|
|
128
|
-
e.type === 'bug_reported'
|
|
129
|
-
).length
|
|
130
|
-
|
|
131
|
-
// Count syncs
|
|
132
|
-
const syncs = weekEvents.filter(e => e.type === 'sync').length
|
|
133
|
-
|
|
134
|
-
// 3. Also aggregate from sessions
|
|
135
|
-
const sessions = stats.legacyStats?.sessions ?? []
|
|
136
|
-
let sessionTasksCompleted = 0
|
|
137
|
-
let sessionFeatures = 0
|
|
138
|
-
const activeDaysSet = new Set<string>()
|
|
139
|
-
|
|
140
|
-
for (const session of sessions) {
|
|
141
|
-
if (session.date && isDateInWeek(session.date, start, end)) {
|
|
142
|
-
activeDaysSet.add(session.date)
|
|
143
|
-
sessionTasksCompleted += session.tasksCompleted || 0
|
|
144
|
-
sessionFeatures += session.featuresShipped || 0
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// Add active days from timeline
|
|
149
|
-
for (const e of weekEvents) {
|
|
150
|
-
if (e.ts) {
|
|
151
|
-
activeDaysSet.add(e.ts.split('T')[0])
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
return {
|
|
156
|
-
year,
|
|
157
|
-
week,
|
|
158
|
-
startDate: start,
|
|
159
|
-
endDate: end,
|
|
160
|
-
shipped,
|
|
161
|
-
tasksCompleted: tasksCompleted + sessionTasksCompleted,
|
|
162
|
-
bugsFixed,
|
|
163
|
-
syncs,
|
|
164
|
-
activeDays: activeDaysSet.size
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Generate plain text report for WhatsApp/email - client friendly
|
|
170
|
-
*/
|
|
171
|
-
export function generateReportText(
|
|
172
|
-
weekData: WeekData | WeekData[],
|
|
173
|
-
projectName: string
|
|
174
|
-
): string {
|
|
175
|
-
const weeks = Array.isArray(weekData) ? weekData : [weekData]
|
|
176
|
-
|
|
177
|
-
if (weeks.length === 0) {
|
|
178
|
-
return 'No weeks selected'
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const lines: string[] = []
|
|
182
|
-
|
|
183
|
-
// Header - clean and professional
|
|
184
|
-
lines.push(`*${projectName}*`)
|
|
185
|
-
|
|
186
|
-
// Date range - human readable
|
|
187
|
-
if (weeks.length === 1) {
|
|
188
|
-
const w = weeks[0]
|
|
189
|
-
lines.push(`Weekly Report: ${formatDateRange(w.startDate, w.endDate)}`)
|
|
190
|
-
} else {
|
|
191
|
-
const firstWeek = weeks[0]
|
|
192
|
-
const lastWeek = weeks[weeks.length - 1]
|
|
193
|
-
lines.push(`Report: ${formatDateRange(firstWeek.startDate, lastWeek.endDate)}`)
|
|
194
|
-
}
|
|
195
|
-
lines.push('')
|
|
196
|
-
|
|
197
|
-
// Aggregate data
|
|
198
|
-
const allShipped = weeks.flatMap(w => w.shipped)
|
|
199
|
-
// Deduplicate by name, keeping first occurrence (with version info)
|
|
200
|
-
const uniqueShipsMap = new Map<string, ShippedItem>()
|
|
201
|
-
for (const ship of allShipped) {
|
|
202
|
-
if (!uniqueShipsMap.has(ship.name)) {
|
|
203
|
-
uniqueShipsMap.set(ship.name, ship)
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
// Sort by date descending (most recent first)
|
|
207
|
-
const uniqueShips = Array.from(uniqueShipsMap.values())
|
|
208
|
-
.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
|
|
209
|
-
|
|
210
|
-
// Group by date
|
|
211
|
-
const shipsByDate = new Map<string, ShippedItem[]>()
|
|
212
|
-
for (const ship of uniqueShips) {
|
|
213
|
-
if (!shipsByDate.has(ship.date)) {
|
|
214
|
-
shipsByDate.set(ship.date, [])
|
|
215
|
-
}
|
|
216
|
-
shipsByDate.get(ship.date)!.push(ship)
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// What we delivered - grouped by date
|
|
220
|
-
if (uniqueShips.length > 0) {
|
|
221
|
-
lines.push('*Shipped:*')
|
|
222
|
-
for (const [date, ships] of shipsByDate.entries()) {
|
|
223
|
-
const dateStr = new Date(date).toLocaleDateString('en-US', {
|
|
224
|
-
weekday: 'short',
|
|
225
|
-
day: 'numeric',
|
|
226
|
-
month: 'short'
|
|
227
|
-
})
|
|
228
|
-
lines.push(`_${dateStr}_`)
|
|
229
|
-
for (const ship of ships) {
|
|
230
|
-
const versionStr = ship.version ? ` (${ship.version})` : ''
|
|
231
|
-
lines.push(`• ${ship.name}${versionStr}`)
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
lines.push('')
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// Aggregate progress metrics
|
|
238
|
-
const totalTasks = weeks.reduce((sum, w) => sum + w.tasksCompleted, 0)
|
|
239
|
-
const totalBugs = weeks.reduce((sum, w) => sum + w.bugsFixed, 0)
|
|
240
|
-
const totalDays = weeks.reduce((sum, w) => sum + w.activeDays, 0)
|
|
241
|
-
|
|
242
|
-
// Progress section
|
|
243
|
-
if (totalTasks > 0 || totalBugs > 0 || totalDays > 0) {
|
|
244
|
-
lines.push('*Progress:*')
|
|
245
|
-
if (totalTasks > 0) {
|
|
246
|
-
lines.push(`• ${totalTasks} task${totalTasks !== 1 ? 's' : ''} completed`)
|
|
247
|
-
}
|
|
248
|
-
if (totalBugs > 0) {
|
|
249
|
-
lines.push(`• ${totalBugs} bug${totalBugs !== 1 ? 's' : ''} fixed`)
|
|
250
|
-
}
|
|
251
|
-
if (totalDays > 0) {
|
|
252
|
-
lines.push(`• ${totalDays} active day${totalDays !== 1 ? 's' : ''}`)
|
|
253
|
-
}
|
|
254
|
-
lines.push('')
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// If nothing happened, be honest
|
|
258
|
-
if (uniqueShips.length === 0 && totalTasks === 0 && totalBugs === 0) {
|
|
259
|
-
lines.push('_In progress, no deliveries this week._')
|
|
260
|
-
lines.push('')
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// Optional: Next steps placeholder
|
|
264
|
-
lines.push('*Next:*')
|
|
265
|
-
lines.push('• [To be defined]')
|
|
266
|
-
|
|
267
|
-
return lines.join('\n')
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Get activity level for a week (for calendar indicator)
|
|
272
|
-
*/
|
|
273
|
-
export function getWeekActivityLevel(
|
|
274
|
-
stats: StatsResult,
|
|
275
|
-
year: number,
|
|
276
|
-
week: number
|
|
277
|
-
): 'none' | 'low' | 'medium' | 'high' {
|
|
278
|
-
const data = filterDataByWeek(stats, year, week)
|
|
279
|
-
const total = data.shipped.length + data.tasksCompleted + data.bugsFixed + data.syncs
|
|
280
|
-
|
|
281
|
-
if (total === 0) return 'none'
|
|
282
|
-
if (total <= 3) return 'low'
|
|
283
|
-
if (total <= 10) return 'medium'
|
|
284
|
-
return 'high'
|
|
285
|
-
}
|