cognova 0.1.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 (205) hide show
  1. package/.env.example +58 -0
  2. package/Claude/CLAUDE.md +92 -0
  3. package/Claude/hooks/lib/__init__.py +1 -0
  4. package/Claude/hooks/lib/hook_client.py +207 -0
  5. package/Claude/hooks/log-event.py +97 -0
  6. package/Claude/hooks/pre-compact.py +46 -0
  7. package/Claude/hooks/session-end.py +26 -0
  8. package/Claude/hooks/session-start.py +35 -0
  9. package/Claude/hooks/stop-extract.py +40 -0
  10. package/Claude/rules/frontmatter.md +54 -0
  11. package/Claude/rules/markdown.md +43 -0
  12. package/Claude/rules/note-organization.md +33 -0
  13. package/Claude/settings.json +54 -0
  14. package/Claude/skills/README.md +136 -0
  15. package/Claude/skills/_lib/__init__.py +1 -0
  16. package/Claude/skills/_lib/api.py +164 -0
  17. package/Claude/skills/_lib/output.py +95 -0
  18. package/Claude/skills/environment/SKILL.md +73 -0
  19. package/Claude/skills/environment/environment.py +239 -0
  20. package/Claude/skills/memory/SKILL.md +153 -0
  21. package/Claude/skills/memory/memory.py +270 -0
  22. package/Claude/skills/project/SKILL.md +105 -0
  23. package/Claude/skills/project/project.py +203 -0
  24. package/Claude/skills/skill-creator/SKILL.md +261 -0
  25. package/Claude/skills/task/SKILL.md +135 -0
  26. package/Claude/skills/task/task.py +310 -0
  27. package/LICENSE +21 -0
  28. package/README.md +176 -0
  29. package/app/app.config.ts +8 -0
  30. package/app/app.vue +39 -0
  31. package/app/assets/css/main.css +10 -0
  32. package/app/components/AppLogo.vue +40 -0
  33. package/app/components/AssistantPanel.client.vue +518 -0
  34. package/app/components/ConfirmModal.vue +84 -0
  35. package/app/components/TemplateMenu.vue +49 -0
  36. package/app/components/agents/AgentActivityChart.client.vue +105 -0
  37. package/app/components/agents/AgentActivityChart.server.vue +25 -0
  38. package/app/components/agents/AgentForm.vue +304 -0
  39. package/app/components/agents/AgentRunModal.vue +154 -0
  40. package/app/components/agents/AgentStatsCards.vue +98 -0
  41. package/app/components/chat/ChatInput.vue +85 -0
  42. package/app/components/chat/ConversationList.vue +78 -0
  43. package/app/components/chat/MessageBubble.vue +81 -0
  44. package/app/components/chat/StreamingMessage.vue +36 -0
  45. package/app/components/chat/ToolCallBlock.vue +77 -0
  46. package/app/components/editor/CodeEditor.client.vue +212 -0
  47. package/app/components/editor/CodeEditorFallback.vue +12 -0
  48. package/app/components/editor/DocumentEditor.vue +326 -0
  49. package/app/components/editor/DocumentMetadata.vue +140 -0
  50. package/app/components/editor/MarkdownEditor.vue +146 -0
  51. package/app/components/files/FileTree.vue +436 -0
  52. package/app/components/hooks/HookActivityChart.client.vue +117 -0
  53. package/app/components/hooks/HookActivityChart.server.vue +25 -0
  54. package/app/components/hooks/HookStatsCards.vue +63 -0
  55. package/app/components/hooks/RecentEventsTable.vue +123 -0
  56. package/app/components/hooks/ToolBreakdownTable.vue +72 -0
  57. package/app/components/search/DashboardSearch.vue +122 -0
  58. package/app/components/tasks/ProjectSelect.vue +35 -0
  59. package/app/components/tasks/TaskCard.vue +182 -0
  60. package/app/components/tasks/TaskDetail.vue +160 -0
  61. package/app/components/tasks/TaskForm.vue +280 -0
  62. package/app/components/tasks/TaskList.vue +69 -0
  63. package/app/components/view/ViewToc.vue +85 -0
  64. package/app/composables/useAgents.ts +153 -0
  65. package/app/composables/useAuth.ts +73 -0
  66. package/app/composables/useChat.ts +298 -0
  67. package/app/composables/useDocument.ts +141 -0
  68. package/app/composables/useEditor.ts +100 -0
  69. package/app/composables/useFileTree.ts +220 -0
  70. package/app/composables/useHookEvents.ts +68 -0
  71. package/app/composables/useMemories.ts +83 -0
  72. package/app/composables/useNotificationBus.ts +154 -0
  73. package/app/composables/usePreferences.ts +131 -0
  74. package/app/composables/useProjects.ts +97 -0
  75. package/app/composables/useSearch.ts +52 -0
  76. package/app/composables/useTasks.ts +201 -0
  77. package/app/composables/useTerminal.ts +135 -0
  78. package/app/layouts/auth.vue +20 -0
  79. package/app/layouts/dashboard.vue +186 -0
  80. package/app/layouts/view.vue +60 -0
  81. package/app/middleware/auth.ts +9 -0
  82. package/app/pages/agents/[id].vue +602 -0
  83. package/app/pages/agents/index.vue +412 -0
  84. package/app/pages/chat.vue +146 -0
  85. package/app/pages/dashboard.vue +80 -0
  86. package/app/pages/docs.vue +131 -0
  87. package/app/pages/hooks.vue +163 -0
  88. package/app/pages/index.vue +249 -0
  89. package/app/pages/login.vue +60 -0
  90. package/app/pages/memories.vue +282 -0
  91. package/app/pages/settings.vue +625 -0
  92. package/app/pages/tasks.vue +312 -0
  93. package/app/pages/view/[uuid].vue +376 -0
  94. package/dist/cli/index.js +2711 -0
  95. package/drizzle.config.ts +10 -0
  96. package/nuxt.config.ts +98 -0
  97. package/package.json +107 -0
  98. package/server/api/agents/[id]/cancel.post.ts +27 -0
  99. package/server/api/agents/[id]/run.post.ts +34 -0
  100. package/server/api/agents/[id]/runs.get.ts +45 -0
  101. package/server/api/agents/[id]/stats.get.ts +94 -0
  102. package/server/api/agents/[id].delete.ts +29 -0
  103. package/server/api/agents/[id].get.ts +25 -0
  104. package/server/api/agents/[id].patch.ts +55 -0
  105. package/server/api/agents/index.get.ts +15 -0
  106. package/server/api/agents/index.post.ts +48 -0
  107. package/server/api/agents/stats.get.ts +86 -0
  108. package/server/api/auth/[...all].ts +5 -0
  109. package/server/api/conversations/[id].delete.ts +16 -0
  110. package/server/api/conversations/[id].get.ts +34 -0
  111. package/server/api/conversations/index.get.ts +17 -0
  112. package/server/api/documents/[id]/index.delete.ts +47 -0
  113. package/server/api/documents/[id]/index.put.ts +102 -0
  114. package/server/api/documents/[id]/public.get.ts +60 -0
  115. package/server/api/documents/[id]/restore.post.ts +65 -0
  116. package/server/api/documents/by-path.post.ts +168 -0
  117. package/server/api/documents/index.get.ts +48 -0
  118. package/server/api/fs/delete.post.ts +41 -0
  119. package/server/api/fs/list.get.ts +99 -0
  120. package/server/api/fs/mkdir.post.ts +44 -0
  121. package/server/api/fs/move.post.ts +68 -0
  122. package/server/api/fs/read.post.ts +48 -0
  123. package/server/api/fs/rename.post.ts +55 -0
  124. package/server/api/fs/write.post.ts +51 -0
  125. package/server/api/health.get.ts +40 -0
  126. package/server/api/home.get.ts +26 -0
  127. package/server/api/hooks/events/index.get.ts +56 -0
  128. package/server/api/hooks/events/index.post.ts +36 -0
  129. package/server/api/hooks/stats.get.ts +99 -0
  130. package/server/api/memory/[id].delete.ts +26 -0
  131. package/server/api/memory/context.get.ts +83 -0
  132. package/server/api/memory/extract.post.ts +42 -0
  133. package/server/api/memory/search.get.ts +70 -0
  134. package/server/api/memory/store.post.ts +31 -0
  135. package/server/api/projects/[id]/index.delete.ts +40 -0
  136. package/server/api/projects/[id]/index.get.ts +25 -0
  137. package/server/api/projects/[id]/index.put.ts +50 -0
  138. package/server/api/projects/index.get.ts +20 -0
  139. package/server/api/projects/index.post.ts +34 -0
  140. package/server/api/secrets/[key].delete.ts +31 -0
  141. package/server/api/secrets/[key].get.ts +30 -0
  142. package/server/api/secrets/[key].put.ts +52 -0
  143. package/server/api/secrets/index.get.ts +20 -0
  144. package/server/api/secrets/index.post.ts +58 -0
  145. package/server/api/tasks/[id]/index.delete.ts +46 -0
  146. package/server/api/tasks/[id]/index.get.ts +24 -0
  147. package/server/api/tasks/[id]/index.put.ts +70 -0
  148. package/server/api/tasks/[id]/restore.post.ts +49 -0
  149. package/server/api/tasks/index.get.ts +53 -0
  150. package/server/api/tasks/index.post.ts +47 -0
  151. package/server/api/tasks/tags.get.ts +21 -0
  152. package/server/api/user/email.patch.ts +56 -0
  153. package/server/db/index.ts +76 -0
  154. package/server/db/migrate.ts +41 -0
  155. package/server/db/schema.ts +345 -0
  156. package/server/db/seed.ts +46 -0
  157. package/server/db/types.ts +28 -0
  158. package/server/drizzle/migrations/0000_brown_george_stacy.sql +34 -0
  159. package/server/drizzle/migrations/0001_stormy_pyro.sql +16 -0
  160. package/server/drizzle/migrations/0002_clean_colossus.sql +50 -0
  161. package/server/drizzle/migrations/0003_fine_joystick.sql +12 -0
  162. package/server/drizzle/migrations/0004_tan_groot.sql +26 -0
  163. package/server/drizzle/migrations/0005_cloudy_lilith.sql +33 -0
  164. package/server/drizzle/migrations/0006_ordinary_retro_girl.sql +13 -0
  165. package/server/drizzle/migrations/0007_flowery_venus.sql +15 -0
  166. package/server/drizzle/migrations/0008_talented_zombie.sql +13 -0
  167. package/server/drizzle/migrations/0009_gray_shen.sql +15 -0
  168. package/server/drizzle/migrations/meta/0000_snapshot.json +230 -0
  169. package/server/drizzle/migrations/meta/0001_snapshot.json +306 -0
  170. package/server/drizzle/migrations/meta/0002_snapshot.json +615 -0
  171. package/server/drizzle/migrations/meta/0003_snapshot.json +730 -0
  172. package/server/drizzle/migrations/meta/0004_snapshot.json +916 -0
  173. package/server/drizzle/migrations/meta/0005_snapshot.json +1127 -0
  174. package/server/drizzle/migrations/meta/0006_snapshot.json +1213 -0
  175. package/server/drizzle/migrations/meta/0007_snapshot.json +1307 -0
  176. package/server/drizzle/migrations/meta/0008_snapshot.json +1390 -0
  177. package/server/drizzle/migrations/meta/0009_snapshot.json +1487 -0
  178. package/server/drizzle/migrations/meta/_journal.json +76 -0
  179. package/server/middleware/auth.ts +79 -0
  180. package/server/plugins/00.env-validate.ts +38 -0
  181. package/server/plugins/01.api-token.ts +31 -0
  182. package/server/plugins/02.database.ts +54 -0
  183. package/server/plugins/03.file-watcher.ts +65 -0
  184. package/server/plugins/04.cron-agents.ts +26 -0
  185. package/server/routes/_ws/chat.ts +252 -0
  186. package/server/routes/notifications.ts +47 -0
  187. package/server/routes/terminal.ts +98 -0
  188. package/server/services/agent-executor.ts +218 -0
  189. package/server/services/cron-scheduler.ts +78 -0
  190. package/server/services/memory-extractor.ts +120 -0
  191. package/server/utils/agent-cleanup.ts +91 -0
  192. package/server/utils/agent-registry.ts +95 -0
  193. package/server/utils/auth.ts +33 -0
  194. package/server/utils/chat-session-manager.ts +59 -0
  195. package/server/utils/crypto.ts +40 -0
  196. package/server/utils/db-guard.ts +12 -0
  197. package/server/utils/db-state.ts +63 -0
  198. package/server/utils/document-sync.ts +207 -0
  199. package/server/utils/frontmatter.ts +84 -0
  200. package/server/utils/notification-bus.ts +60 -0
  201. package/server/utils/path-validator.ts +55 -0
  202. package/server/utils/pty-manager.ts +130 -0
  203. package/shared/types/index.ts +604 -0
  204. package/shared/utils/language-detection.ts +87 -0
  205. package/tsconfig.json +10 -0
@@ -0,0 +1,131 @@
1
+ <script setup lang="ts">
2
+ definePageMeta({
3
+ layout: 'dashboard',
4
+ middleware: 'auth'
5
+ })
6
+
7
+ const route = useRoute()
8
+
9
+ const {
10
+ document,
11
+ metadata,
12
+ body,
13
+ filePath,
14
+ loading,
15
+ saveStatus,
16
+ isDirty,
17
+ metadataDirty,
18
+ loadDocument,
19
+ updateBody,
20
+ updateMetadata,
21
+ saveNow
22
+ } = useDocument()
23
+
24
+ const { lastDocumentPath } = usePreferences()
25
+
26
+ async function handleFileSelect(path: string) {
27
+ await loadDocument(path)
28
+ lastDocumentPath.value = path
29
+ }
30
+
31
+ // Load document from query parameter or last viewed on mount
32
+ onMounted(async () => {
33
+ const pathParam = route.query.path as string | undefined
34
+ if (pathParam) {
35
+ await loadDocument(pathParam)
36
+ lastDocumentPath.value = pathParam
37
+ } else if (lastDocumentPath.value) {
38
+ await loadDocument(lastDocumentPath.value)
39
+ }
40
+ })
41
+ </script>
42
+
43
+ <template>
44
+ <div class="flex flex-1 min-w-0">
45
+ <UDashboardPanel
46
+ id="docs-filetree"
47
+ collapsible
48
+ resizable
49
+ :min-size="12"
50
+ :default-size="16"
51
+ :max-size="24"
52
+ class="hidden lg:flex"
53
+ >
54
+ <template #body>
55
+ <FilesFileTree
56
+ class="h-full"
57
+ @select="handleFileSelect"
58
+ />
59
+ </template>
60
+ </UDashboardPanel>
61
+
62
+ <UDashboardPanel
63
+ id="docs-editor"
64
+ grow
65
+ :ui="{ body: 'sm:py-0' }"
66
+ >
67
+ <template #header>
68
+ <UDashboardNavbar>
69
+ <template #title>
70
+ <UDashboardSidebarCollapse />
71
+ Editor
72
+ </template>
73
+ <template #right>
74
+ <UColorModeButton />
75
+ <UDrawer>
76
+ <UButton
77
+ icon="i-lucide-folder-tree"
78
+ class="block lg:hidden"
79
+ />
80
+ <template #content>
81
+ <FilesFileTree
82
+ class="h-full"
83
+ @select="handleFileSelect"
84
+ />
85
+ </template>
86
+ </UDrawer>
87
+ </template>
88
+ </UDashboardNavbar>
89
+ </template>
90
+
91
+ <template #body>
92
+ <div
93
+ v-if="loading"
94
+ class="flex-1 flex items-center justify-center h-full"
95
+ >
96
+ <UIcon
97
+ name="i-lucide-loader-2"
98
+ class="size-6 animate-spin text-dimmed"
99
+ />
100
+ </div>
101
+ <div
102
+ v-else-if="!filePath"
103
+ class="flex-1 flex items-center justify-center h-full text-dimmed"
104
+ >
105
+ <div class="text-center">
106
+ <UIcon
107
+ name="i-lucide-file-text"
108
+ class="size-32 mx-auto mb-4 opacity-50"
109
+ />
110
+ <p>Select a file to edit</p>
111
+ </div>
112
+ </div>
113
+ <EditorDocumentEditor
114
+ v-else-if="metadata && document"
115
+ :key="filePath"
116
+ :document="document"
117
+ :body="body"
118
+ :metadata="metadata"
119
+ :file-path="filePath"
120
+ :save-status="saveStatus"
121
+ :is-dirty="isDirty"
122
+ :metadata-dirty="metadataDirty"
123
+ class="h-full"
124
+ @update:body="updateBody"
125
+ @update:metadata="updateMetadata"
126
+ @save="saveNow"
127
+ />
128
+ </template>
129
+ </UDashboardPanel>
130
+ </div>
131
+ </template>
@@ -0,0 +1,163 @@
1
+ <script setup lang="ts">
2
+ import type { HookEvent, HookEventStats, StatsPeriod } from '~~/shared/types'
3
+
4
+ definePageMeta({
5
+ layout: 'dashboard',
6
+ middleware: 'auth'
7
+ })
8
+
9
+ const { fetchEvents, fetchStats } = useHookEvents()
10
+ const { agentStatsPeriod } = usePreferences()
11
+
12
+ // State
13
+ const events = ref<HookEvent[]>([])
14
+ const stats = ref<HookEventStats | null>(null)
15
+ const loading = ref(false)
16
+ const period = ref<StatsPeriod>(agentStatsPeriod.value)
17
+
18
+ // Period options
19
+ const periodOptions = [
20
+ { label: '24h', value: '24h' as StatsPeriod },
21
+ { label: '7d', value: '7d' as StatsPeriod },
22
+ { label: '30d', value: '30d' as StatsPeriod }
23
+ ]
24
+
25
+ // Load data
26
+ async function loadData() {
27
+ loading.value = true
28
+ try {
29
+ const [statsData, eventsData] = await Promise.all([
30
+ fetchStats(period.value),
31
+ fetchEvents({ limit: 50 })
32
+ ])
33
+ stats.value = statsData
34
+ events.value = eventsData
35
+ } catch (e) {
36
+ console.error('Failed to load hook data:', e)
37
+ } finally {
38
+ loading.value = false
39
+ }
40
+ }
41
+
42
+ // Watch period changes
43
+ watch(period, () => {
44
+ agentStatsPeriod.value = period.value
45
+ loadData()
46
+ })
47
+
48
+ // Load on mount
49
+ onMounted(loadData)
50
+ </script>
51
+
52
+ <template>
53
+ <div class="contents">
54
+ <UDashboardPanel
55
+ id="hooks"
56
+ grow
57
+ >
58
+ <template #header>
59
+ <UDashboardNavbar title="Hook Analytics">
60
+ <template #right>
61
+ <UFieldGroup>
62
+ <UButton
63
+ v-for="opt in periodOptions"
64
+ :key="opt.value"
65
+ :color="period === opt.value ? 'primary' : 'neutral'"
66
+ :variant="period === opt.value ? 'solid' : 'ghost'"
67
+ size="sm"
68
+ @click="period = opt.value"
69
+ >
70
+ {{ opt.label }}
71
+ </UButton>
72
+ </UFieldGroup>
73
+ </template>
74
+ </UDashboardNavbar>
75
+ </template>
76
+
77
+ <template #body>
78
+ <div class="p-4 space-y-6">
79
+ <!-- Stats Cards -->
80
+ <HooksHookStatsCards
81
+ :stats="stats"
82
+ :loading="loading"
83
+ />
84
+
85
+ <!-- Activity Chart -->
86
+ <HooksHookActivityChart
87
+ v-if="stats && stats.dailyActivity.length > 0"
88
+ :data="stats.dailyActivity"
89
+ title="Daily Activity"
90
+ />
91
+
92
+ <!-- Two column layout for tables -->
93
+ <div class="grid lg:grid-cols-2 gap-6">
94
+ <!-- Tool Breakdown -->
95
+ <HooksToolBreakdownTable
96
+ :data="stats?.toolBreakdown ?? []"
97
+ :loading="loading"
98
+ />
99
+
100
+ <!-- Event Types -->
101
+ <UCard v-if="stats">
102
+ <template #header>
103
+ <p class="text-sm font-medium">
104
+ Events by Type
105
+ </p>
106
+ </template>
107
+
108
+ <div
109
+ v-if="!stats.eventsByType || Object.keys(stats.eventsByType).length === 0"
110
+ class="text-center text-muted py-8"
111
+ >
112
+ No events by type data
113
+ </div>
114
+
115
+ <div
116
+ v-else
117
+ class="space-y-3"
118
+ >
119
+ <div
120
+ v-for="(count, type) in stats.eventsByType"
121
+ :key="type"
122
+ class="flex items-center justify-between"
123
+ >
124
+ <span class="text-sm">{{ type }}</span>
125
+ <UBadge
126
+ color="neutral"
127
+ variant="subtle"
128
+ >
129
+ {{ count }}
130
+ </UBadge>
131
+ </div>
132
+ </div>
133
+ </UCard>
134
+ </div>
135
+
136
+ <!-- Recent Events -->
137
+ <HooksRecentEventsTable
138
+ :events="events"
139
+ :loading="loading"
140
+ />
141
+
142
+ <!-- Empty state -->
143
+ <div
144
+ v-if="!loading && events.length === 0 && !stats?.totalEvents"
145
+ class="flex flex-col items-center justify-center h-64 text-neutral-500"
146
+ >
147
+ <UIcon
148
+ name="i-lucide-webhook"
149
+ class="w-12 h-12 mb-4"
150
+ />
151
+ <p class="text-lg font-medium">
152
+ No hook events yet
153
+ </p>
154
+ <p class="text-sm text-center max-w-md">
155
+ Hook events will appear here once Claude Code hooks are triggered.
156
+ Make sure your hooks are configured in ~/.claude/settings.json
157
+ </p>
158
+ </div>
159
+ </div>
160
+ </template>
161
+ </UDashboardPanel>
162
+ </div>
163
+ </template>
@@ -0,0 +1,249 @@
1
+ <script setup lang="ts">
2
+ definePageMeta({
3
+ layout: 'view'
4
+ })
5
+
6
+ const { isAuthenticated } = useAuth()
7
+
8
+ // Redirect authenticated users to dashboard (disabled for public home page)
9
+ // watch([isAuthenticated, isPending], ([authenticated, pending]) => {
10
+ // if (!pending && authenticated)
11
+ // navigateTo('/dashboard')
12
+ // }, { immediate: true })
13
+
14
+ // Fetch home page content
15
+ const { data } = await useFetch<{ data: { hasCustomHome: boolean, content: string | null } }>('/api/home')
16
+
17
+ const hasCustomContent = computed(() => data.value?.data?.hasCustomHome ?? false)
18
+ const customContent = computed(() => data.value?.data?.content ?? '')
19
+
20
+ // Hero links
21
+ const heroLinks = computed(() => {
22
+ const links = [
23
+ {
24
+ label: 'Get Started',
25
+ to: '/login',
26
+ icon: 'i-lucide-log-in'
27
+ },
28
+ {
29
+ label: 'View on GitHub',
30
+ to: 'https://github.com/Patrity/cognova',
31
+ target: '_blank',
32
+ color: 'neutral' as const,
33
+ variant: 'subtle' as const,
34
+ icon: 'i-simple-icons-github'
35
+ }
36
+ ]
37
+ if (isAuthenticated.value) {
38
+ links[0] = {
39
+ label: 'Dashboard',
40
+ to: '/dashboard',
41
+ icon: 'i-lucide-home'
42
+ }
43
+ }
44
+ return links
45
+ })
46
+
47
+ // Core features
48
+ const coreFeatures = [
49
+ {
50
+ title: 'Terminal Integration',
51
+ description: 'Native terminal support with node-pty for running commands directly in your workflow.',
52
+ icon: 'i-lucide-terminal'
53
+ },
54
+ {
55
+ title: 'Claude Code Support',
56
+ description: 'Built-in integration with Claude Code for AI-assisted development and knowledge management.',
57
+ icon: 'i-lucide-bot'
58
+ },
59
+ {
60
+ title: 'Custom Skills',
61
+ description: 'Extend functionality with custom skills that automate common tasks and workflows.',
62
+ icon: 'i-lucide-sparkles'
63
+ },
64
+ {
65
+ title: 'Task Management',
66
+ description: 'Track tasks across projects with priorities, due dates, and smart filtering.',
67
+ icon: 'i-lucide-check-square'
68
+ }
69
+ ]
70
+
71
+ // Additional features for the grid
72
+ const additionalFeatures = [
73
+ {
74
+ title: 'Markdown Editor',
75
+ description: 'Full-featured markdown editor with live preview, syntax highlighting, and frontmatter support.',
76
+ icon: 'i-lucide-file-text'
77
+ },
78
+ {
79
+ title: 'Document Sharing',
80
+ description: 'Share documents publicly or with private links. Control visibility per document.',
81
+ icon: 'i-lucide-share-2'
82
+ },
83
+ {
84
+ title: 'Scheduled Reminders',
85
+ description: 'Set reminders and scheduled tasks that notify you at the right time.',
86
+ icon: 'i-lucide-bell'
87
+ },
88
+ {
89
+ title: 'File Sync',
90
+ description: 'Automatic synchronization between your local vault and the database.',
91
+ icon: 'i-lucide-refresh-cw'
92
+ },
93
+ {
94
+ title: 'Self-Hosted',
95
+ description: 'Own your data. Deploy anywhere with Docker or your preferred platform.',
96
+ icon: 'i-lucide-server'
97
+ },
98
+ {
99
+ title: 'Dark Mode',
100
+ description: 'Beautiful light and dark themes that respect your system preferences.',
101
+ icon: 'i-lucide-moon'
102
+ }
103
+ ]
104
+
105
+ // Tech stack for carousel
106
+ const techStack = [
107
+ { name: 'Nuxt', icon: 'i-simple-icons-nuxtdotjs' },
108
+ { name: 'Vue', icon: 'i-simple-icons-vuedotjs' },
109
+ { name: 'TypeScript', icon: 'i-simple-icons-typescript' },
110
+ { name: 'Tailwind CSS', icon: 'i-simple-icons-tailwindcss' },
111
+ { name: 'PostgreSQL', icon: 'i-simple-icons-postgresql' },
112
+ { name: 'Docker', icon: 'i-simple-icons-docker' },
113
+ { name: 'Drizzle', icon: 'i-simple-icons-drizzle' },
114
+ { name: 'Claude', icon: 'i-simple-icons-anthropic' }
115
+ ]
116
+
117
+ // CTA links
118
+ const ctaLinks = computed(() => {
119
+ const links = [
120
+ {
121
+ label: 'Get Started',
122
+ to: '/login',
123
+ color: 'neutral' as const
124
+ },
125
+ {
126
+ label: 'Read the Docs',
127
+ to: 'https://github.com/Patrity/cognova#readme',
128
+ target: '_blank',
129
+ color: 'neutral' as const,
130
+ variant: 'subtle' as const,
131
+ trailingIcon: 'i-lucide-arrow-right'
132
+ }
133
+ ]
134
+ if (isAuthenticated.value) {
135
+ links[0] = {
136
+ label: 'Dashboard',
137
+ to: '/dashboard',
138
+ color: 'neutral'
139
+ }
140
+ }
141
+ return links
142
+ })
143
+ </script>
144
+
145
+ <template>
146
+ <!-- Custom home page from index.md -->
147
+ <UContainer
148
+ v-if="hasCustomContent"
149
+ class="py-12"
150
+ >
151
+ <div class="prose prose-primary dark:prose-invert max-w-none">
152
+ <MDC :value="customContent" />
153
+ </div>
154
+ </UContainer>
155
+
156
+ <!-- Default home page -->
157
+ <div v-else>
158
+ <!-- Hero Section -->
159
+ <UPageHero
160
+ title="Your Personal Knowledge System"
161
+ description="A self-hosted knowledge management platform for capturing thoughts, organizing tasks, and building your digital brain. Powered by Claude Code integration."
162
+ :links="heroLinks"
163
+ >
164
+ <template #top>
165
+ <div class="flex justify-center mt-16 -mb-24">
166
+ <div class="p-4 rounded-full bg-primary/10">
167
+ <UIcon
168
+ name="i-lucide-brain"
169
+ class="size-24 text-primary"
170
+ />
171
+ </div>
172
+ </div>
173
+ </template>
174
+ </UPageHero>
175
+
176
+ <!-- Core Features Section -->
177
+ <UPageSection
178
+ headline="Features"
179
+ title="Everything you need for knowledge management"
180
+ description="Cognova combines powerful tools for note-taking, task management, and AI-assisted workflows in one self-hosted solution."
181
+ :features="coreFeatures"
182
+ />
183
+
184
+ <USeparator />
185
+
186
+ <!-- Additional Features Grid -->
187
+ <UPageSection
188
+ title="And much more..."
189
+ description="Built with modern technologies and extensible architecture."
190
+ :ui="{ root: 'bg-muted' }"
191
+ class="w-full"
192
+ >
193
+ <UPageGrid>
194
+ <UPageCard
195
+ v-for="feature in additionalFeatures"
196
+ :key="feature.title"
197
+ :title="feature.title"
198
+ :description="feature.description"
199
+ :icon="feature.icon"
200
+ variant="subtle"
201
+ spotlight
202
+ />
203
+ </UPageGrid>
204
+ </UPageSection>
205
+
206
+ <USeparator />
207
+
208
+ <!-- Tech Stack Section -->
209
+ <UPageSection
210
+ headline="Built With"
211
+ title="Modern, battle-tested technologies"
212
+ description="Cognova is built on a solid foundation of open-source tools."
213
+ >
214
+ <UCarousel
215
+ :items="techStack"
216
+ :ui="{
217
+ item: 'basis-1/3 md:basis-1/4 lg:basis-1/6'
218
+ }"
219
+ class="w-full"
220
+ arrows
221
+ loop
222
+ :autoplay="{ delay: 2000 }"
223
+ >
224
+ <template #default="{ item }">
225
+ <div class="flex flex-col items-center gap-3 p-6">
226
+ <div class="p-4 rounded-xl bg-default border border-default">
227
+ <UIcon
228
+ :name="item.icon"
229
+ class="size-10 text-muted"
230
+ />
231
+ </div>
232
+ <span class="text-sm font-medium text-muted">{{ item.name }}</span>
233
+ </div>
234
+ </template>
235
+ </UCarousel>
236
+ </UPageSection>
237
+
238
+ <USeparator />
239
+
240
+ <!-- CTA Section -->
241
+ <UPageCTA
242
+ title="Ready to build your knowledge system?"
243
+ description="Get started in minutes. Self-host with Docker or deploy to your favorite cloud platform."
244
+ :links="ctaLinks"
245
+ variant="subtle"
246
+ class="mb-16"
247
+ />
248
+ </div>
249
+ </template>
@@ -0,0 +1,60 @@
1
+ <script setup lang="ts">
2
+ definePageMeta({ layout: 'auth' })
3
+
4
+ const { login, isAuthenticated } = useAuth()
5
+ const toast = useToast()
6
+
7
+ const loading = ref(false)
8
+
9
+ const fields = [
10
+ {
11
+ name: 'email',
12
+ type: 'email' as const,
13
+ label: 'Email',
14
+ placeholder: 'admin@example.com',
15
+ required: true
16
+ },
17
+ {
18
+ name: 'password',
19
+ type: 'password' as const,
20
+ label: 'Password',
21
+ placeholder: 'Enter your password',
22
+ required: true
23
+ }
24
+ ]
25
+
26
+ // Redirect if already authenticated
27
+ watchEffect(() => {
28
+ if (isAuthenticated.value) navigateTo('/')
29
+ })
30
+
31
+ async function handleSubmit(event: { data: { email: string, password: string } }) {
32
+ loading.value = true
33
+
34
+ const result = await login(event.data.email, event.data.password)
35
+
36
+ if (result.error) {
37
+ toast.add({
38
+ title: 'Login failed',
39
+ description: result.error.message || 'Invalid email or password',
40
+ color: 'error',
41
+ icon: 'i-lucide-alert-circle'
42
+ })
43
+ } else {
44
+ navigateTo('/')
45
+ }
46
+
47
+ loading.value = false
48
+ }
49
+ </script>
50
+
51
+ <template>
52
+ <UAuthForm
53
+ title="Sign In"
54
+ description="Enter your credentials to access your account"
55
+ icon="i-lucide-brain"
56
+ :fields="fields"
57
+ :submit="{ label: 'Sign In', loading }"
58
+ @submit="handleSubmit"
59
+ />
60
+ </template>