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.
- package/.env.example +58 -0
- package/Claude/CLAUDE.md +92 -0
- package/Claude/hooks/lib/__init__.py +1 -0
- package/Claude/hooks/lib/hook_client.py +207 -0
- package/Claude/hooks/log-event.py +97 -0
- package/Claude/hooks/pre-compact.py +46 -0
- package/Claude/hooks/session-end.py +26 -0
- package/Claude/hooks/session-start.py +35 -0
- package/Claude/hooks/stop-extract.py +40 -0
- package/Claude/rules/frontmatter.md +54 -0
- package/Claude/rules/markdown.md +43 -0
- package/Claude/rules/note-organization.md +33 -0
- package/Claude/settings.json +54 -0
- package/Claude/skills/README.md +136 -0
- package/Claude/skills/_lib/__init__.py +1 -0
- package/Claude/skills/_lib/api.py +164 -0
- package/Claude/skills/_lib/output.py +95 -0
- package/Claude/skills/environment/SKILL.md +73 -0
- package/Claude/skills/environment/environment.py +239 -0
- package/Claude/skills/memory/SKILL.md +153 -0
- package/Claude/skills/memory/memory.py +270 -0
- package/Claude/skills/project/SKILL.md +105 -0
- package/Claude/skills/project/project.py +203 -0
- package/Claude/skills/skill-creator/SKILL.md +261 -0
- package/Claude/skills/task/SKILL.md +135 -0
- package/Claude/skills/task/task.py +310 -0
- package/LICENSE +21 -0
- package/README.md +176 -0
- package/app/app.config.ts +8 -0
- package/app/app.vue +39 -0
- package/app/assets/css/main.css +10 -0
- package/app/components/AppLogo.vue +40 -0
- package/app/components/AssistantPanel.client.vue +518 -0
- package/app/components/ConfirmModal.vue +84 -0
- package/app/components/TemplateMenu.vue +49 -0
- package/app/components/agents/AgentActivityChart.client.vue +105 -0
- package/app/components/agents/AgentActivityChart.server.vue +25 -0
- package/app/components/agents/AgentForm.vue +304 -0
- package/app/components/agents/AgentRunModal.vue +154 -0
- package/app/components/agents/AgentStatsCards.vue +98 -0
- package/app/components/chat/ChatInput.vue +85 -0
- package/app/components/chat/ConversationList.vue +78 -0
- package/app/components/chat/MessageBubble.vue +81 -0
- package/app/components/chat/StreamingMessage.vue +36 -0
- package/app/components/chat/ToolCallBlock.vue +77 -0
- package/app/components/editor/CodeEditor.client.vue +212 -0
- package/app/components/editor/CodeEditorFallback.vue +12 -0
- package/app/components/editor/DocumentEditor.vue +326 -0
- package/app/components/editor/DocumentMetadata.vue +140 -0
- package/app/components/editor/MarkdownEditor.vue +146 -0
- package/app/components/files/FileTree.vue +436 -0
- package/app/components/hooks/HookActivityChart.client.vue +117 -0
- package/app/components/hooks/HookActivityChart.server.vue +25 -0
- package/app/components/hooks/HookStatsCards.vue +63 -0
- package/app/components/hooks/RecentEventsTable.vue +123 -0
- package/app/components/hooks/ToolBreakdownTable.vue +72 -0
- package/app/components/search/DashboardSearch.vue +122 -0
- package/app/components/tasks/ProjectSelect.vue +35 -0
- package/app/components/tasks/TaskCard.vue +182 -0
- package/app/components/tasks/TaskDetail.vue +160 -0
- package/app/components/tasks/TaskForm.vue +280 -0
- package/app/components/tasks/TaskList.vue +69 -0
- package/app/components/view/ViewToc.vue +85 -0
- package/app/composables/useAgents.ts +153 -0
- package/app/composables/useAuth.ts +73 -0
- package/app/composables/useChat.ts +298 -0
- package/app/composables/useDocument.ts +141 -0
- package/app/composables/useEditor.ts +100 -0
- package/app/composables/useFileTree.ts +220 -0
- package/app/composables/useHookEvents.ts +68 -0
- package/app/composables/useMemories.ts +83 -0
- package/app/composables/useNotificationBus.ts +154 -0
- package/app/composables/usePreferences.ts +131 -0
- package/app/composables/useProjects.ts +97 -0
- package/app/composables/useSearch.ts +52 -0
- package/app/composables/useTasks.ts +201 -0
- package/app/composables/useTerminal.ts +135 -0
- package/app/layouts/auth.vue +20 -0
- package/app/layouts/dashboard.vue +186 -0
- package/app/layouts/view.vue +60 -0
- package/app/middleware/auth.ts +9 -0
- package/app/pages/agents/[id].vue +602 -0
- package/app/pages/agents/index.vue +412 -0
- package/app/pages/chat.vue +146 -0
- package/app/pages/dashboard.vue +80 -0
- package/app/pages/docs.vue +131 -0
- package/app/pages/hooks.vue +163 -0
- package/app/pages/index.vue +249 -0
- package/app/pages/login.vue +60 -0
- package/app/pages/memories.vue +282 -0
- package/app/pages/settings.vue +625 -0
- package/app/pages/tasks.vue +312 -0
- package/app/pages/view/[uuid].vue +376 -0
- package/dist/cli/index.js +2711 -0
- package/drizzle.config.ts +10 -0
- package/nuxt.config.ts +98 -0
- package/package.json +107 -0
- package/server/api/agents/[id]/cancel.post.ts +27 -0
- package/server/api/agents/[id]/run.post.ts +34 -0
- package/server/api/agents/[id]/runs.get.ts +45 -0
- package/server/api/agents/[id]/stats.get.ts +94 -0
- package/server/api/agents/[id].delete.ts +29 -0
- package/server/api/agents/[id].get.ts +25 -0
- package/server/api/agents/[id].patch.ts +55 -0
- package/server/api/agents/index.get.ts +15 -0
- package/server/api/agents/index.post.ts +48 -0
- package/server/api/agents/stats.get.ts +86 -0
- package/server/api/auth/[...all].ts +5 -0
- package/server/api/conversations/[id].delete.ts +16 -0
- package/server/api/conversations/[id].get.ts +34 -0
- package/server/api/conversations/index.get.ts +17 -0
- package/server/api/documents/[id]/index.delete.ts +47 -0
- package/server/api/documents/[id]/index.put.ts +102 -0
- package/server/api/documents/[id]/public.get.ts +60 -0
- package/server/api/documents/[id]/restore.post.ts +65 -0
- package/server/api/documents/by-path.post.ts +168 -0
- package/server/api/documents/index.get.ts +48 -0
- package/server/api/fs/delete.post.ts +41 -0
- package/server/api/fs/list.get.ts +99 -0
- package/server/api/fs/mkdir.post.ts +44 -0
- package/server/api/fs/move.post.ts +68 -0
- package/server/api/fs/read.post.ts +48 -0
- package/server/api/fs/rename.post.ts +55 -0
- package/server/api/fs/write.post.ts +51 -0
- package/server/api/health.get.ts +40 -0
- package/server/api/home.get.ts +26 -0
- package/server/api/hooks/events/index.get.ts +56 -0
- package/server/api/hooks/events/index.post.ts +36 -0
- package/server/api/hooks/stats.get.ts +99 -0
- package/server/api/memory/[id].delete.ts +26 -0
- package/server/api/memory/context.get.ts +83 -0
- package/server/api/memory/extract.post.ts +42 -0
- package/server/api/memory/search.get.ts +70 -0
- package/server/api/memory/store.post.ts +31 -0
- package/server/api/projects/[id]/index.delete.ts +40 -0
- package/server/api/projects/[id]/index.get.ts +25 -0
- package/server/api/projects/[id]/index.put.ts +50 -0
- package/server/api/projects/index.get.ts +20 -0
- package/server/api/projects/index.post.ts +34 -0
- package/server/api/secrets/[key].delete.ts +31 -0
- package/server/api/secrets/[key].get.ts +30 -0
- package/server/api/secrets/[key].put.ts +52 -0
- package/server/api/secrets/index.get.ts +20 -0
- package/server/api/secrets/index.post.ts +58 -0
- package/server/api/tasks/[id]/index.delete.ts +46 -0
- package/server/api/tasks/[id]/index.get.ts +24 -0
- package/server/api/tasks/[id]/index.put.ts +70 -0
- package/server/api/tasks/[id]/restore.post.ts +49 -0
- package/server/api/tasks/index.get.ts +53 -0
- package/server/api/tasks/index.post.ts +47 -0
- package/server/api/tasks/tags.get.ts +21 -0
- package/server/api/user/email.patch.ts +56 -0
- package/server/db/index.ts +76 -0
- package/server/db/migrate.ts +41 -0
- package/server/db/schema.ts +345 -0
- package/server/db/seed.ts +46 -0
- package/server/db/types.ts +28 -0
- package/server/drizzle/migrations/0000_brown_george_stacy.sql +34 -0
- package/server/drizzle/migrations/0001_stormy_pyro.sql +16 -0
- package/server/drizzle/migrations/0002_clean_colossus.sql +50 -0
- package/server/drizzle/migrations/0003_fine_joystick.sql +12 -0
- package/server/drizzle/migrations/0004_tan_groot.sql +26 -0
- package/server/drizzle/migrations/0005_cloudy_lilith.sql +33 -0
- package/server/drizzle/migrations/0006_ordinary_retro_girl.sql +13 -0
- package/server/drizzle/migrations/0007_flowery_venus.sql +15 -0
- package/server/drizzle/migrations/0008_talented_zombie.sql +13 -0
- package/server/drizzle/migrations/0009_gray_shen.sql +15 -0
- package/server/drizzle/migrations/meta/0000_snapshot.json +230 -0
- package/server/drizzle/migrations/meta/0001_snapshot.json +306 -0
- package/server/drizzle/migrations/meta/0002_snapshot.json +615 -0
- package/server/drizzle/migrations/meta/0003_snapshot.json +730 -0
- package/server/drizzle/migrations/meta/0004_snapshot.json +916 -0
- package/server/drizzle/migrations/meta/0005_snapshot.json +1127 -0
- package/server/drizzle/migrations/meta/0006_snapshot.json +1213 -0
- package/server/drizzle/migrations/meta/0007_snapshot.json +1307 -0
- package/server/drizzle/migrations/meta/0008_snapshot.json +1390 -0
- package/server/drizzle/migrations/meta/0009_snapshot.json +1487 -0
- package/server/drizzle/migrations/meta/_journal.json +76 -0
- package/server/middleware/auth.ts +79 -0
- package/server/plugins/00.env-validate.ts +38 -0
- package/server/plugins/01.api-token.ts +31 -0
- package/server/plugins/02.database.ts +54 -0
- package/server/plugins/03.file-watcher.ts +65 -0
- package/server/plugins/04.cron-agents.ts +26 -0
- package/server/routes/_ws/chat.ts +252 -0
- package/server/routes/notifications.ts +47 -0
- package/server/routes/terminal.ts +98 -0
- package/server/services/agent-executor.ts +218 -0
- package/server/services/cron-scheduler.ts +78 -0
- package/server/services/memory-extractor.ts +120 -0
- package/server/utils/agent-cleanup.ts +91 -0
- package/server/utils/agent-registry.ts +95 -0
- package/server/utils/auth.ts +33 -0
- package/server/utils/chat-session-manager.ts +59 -0
- package/server/utils/crypto.ts +40 -0
- package/server/utils/db-guard.ts +12 -0
- package/server/utils/db-state.ts +63 -0
- package/server/utils/document-sync.ts +207 -0
- package/server/utils/frontmatter.ts +84 -0
- package/server/utils/notification-bus.ts +60 -0
- package/server/utils/path-validator.ts +55 -0
- package/server/utils/pty-manager.ts +130 -0
- package/shared/types/index.ts +604 -0
- package/shared/utils/language-detection.ts +87 -0
- 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>
|