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,310 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Task Management Skill for Cognova
4
+
5
+ Usage:
6
+ python task.py create <title> [options]
7
+ python task.py list [filters]
8
+ python task.py update <id> [options]
9
+ python task.py done <id_or_search>
10
+ python task.py delete <id>
11
+ """
12
+
13
+ import argparse
14
+ import sys
15
+ from datetime import datetime, timedelta
16
+ from pathlib import Path
17
+
18
+ sys.path.insert(0, str(Path(__file__).parent.parent / '_lib'))
19
+
20
+ from api import get, post, put, delete
21
+ from output import success, error, info, format_task
22
+
23
+
24
+ def parse_date(date_str: str) -> str | None:
25
+ """Parse natural language date to ISO format."""
26
+ if not date_str:
27
+ return None
28
+
29
+ lower = date_str.lower().strip()
30
+ today = datetime.now()
31
+
32
+ if lower == 'today':
33
+ return today.strftime('%Y-%m-%d')
34
+ elif lower == 'tomorrow':
35
+ return (today + timedelta(days=1)).strftime('%Y-%m-%d')
36
+ elif lower == 'next week':
37
+ return (today + timedelta(weeks=1)).strftime('%Y-%m-%d')
38
+ elif lower in ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']:
39
+ days = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']
40
+ target = days.index(lower)
41
+ current = today.weekday()
42
+ delta = (target - current) % 7
43
+ if delta == 0:
44
+ delta = 7
45
+ return (today + timedelta(days=delta)).strftime('%Y-%m-%d')
46
+
47
+ try:
48
+ parsed = datetime.strptime(date_str, '%Y-%m-%d')
49
+ return parsed.strftime('%Y-%m-%d')
50
+ except ValueError:
51
+ pass
52
+
53
+ return date_str
54
+
55
+
56
+ def find_project(name: str) -> dict | None:
57
+ """Search for a project by name."""
58
+ ok, projects = get('/projects')
59
+ if not ok:
60
+ return None
61
+
62
+ for p in projects:
63
+ if p['name'].lower() == name.lower():
64
+ return p
65
+
66
+ matches = [p for p in projects if name.lower() in p['name'].lower()]
67
+
68
+ if len(matches) == 1:
69
+ return matches[0]
70
+ elif len(matches) > 1:
71
+ print("Multiple projects match:", file=sys.stderr)
72
+ for p in matches:
73
+ print(f" - {p['name']} (ID: {p['id'][:8]})", file=sys.stderr)
74
+ print("\nPlease be more specific.", file=sys.stderr)
75
+ return None
76
+
77
+ return None
78
+
79
+
80
+ def find_task_by_id(id_prefix: str) -> str | None:
81
+ """Find a task by ID prefix."""
82
+ ok, tasks = get('/tasks', {'includeDeleted': 'false'})
83
+ if not ok:
84
+ return None
85
+
86
+ for task in tasks:
87
+ if task['id'].startswith(id_prefix):
88
+ return task['id']
89
+
90
+ return None
91
+
92
+
93
+ def cmd_create(args):
94
+ """Create a new task."""
95
+ data = {
96
+ 'title': args.title,
97
+ 'priority': args.priority or 2,
98
+ }
99
+
100
+ if args.description:
101
+ data['description'] = args.description
102
+
103
+ if args.due:
104
+ data['dueDate'] = parse_date(args.due)
105
+
106
+ if args.tags:
107
+ data['tags'] = [t.strip() for t in args.tags.split(',')]
108
+
109
+ if args.project:
110
+ project = find_project(args.project)
111
+ if project:
112
+ data['projectId'] = project['id']
113
+ info(f"Associated with project: {project['name']}")
114
+ else:
115
+ info(f"No project found matching '{args.project}'. Task created without project.")
116
+
117
+ ok, result = post('/tasks', data)
118
+ if ok:
119
+ success(f"Created task: {result['title']}", result)
120
+ else:
121
+ error(f"Failed to create task: {result}")
122
+ sys.exit(1)
123
+
124
+
125
+ def cmd_list(args):
126
+ """List tasks with filters."""
127
+ params = {}
128
+
129
+ if args.status:
130
+ params['status'] = args.status
131
+ if args.project:
132
+ project = find_project(args.project)
133
+ if project:
134
+ params['projectId'] = project['id']
135
+ if args.search:
136
+ params['search'] = args.search
137
+
138
+ ok, tasks = get('/tasks', params)
139
+ if not ok:
140
+ error(f"Failed to fetch tasks: {tasks}")
141
+ sys.exit(1)
142
+
143
+ if args.due:
144
+ today = datetime.now().date()
145
+ filtered = []
146
+ for t in tasks:
147
+ if not t.get('dueDate'):
148
+ continue
149
+ try:
150
+ due = datetime.fromisoformat(t['dueDate'].replace('Z', '+00:00')).date()
151
+ except (ValueError, AttributeError):
152
+ continue
153
+
154
+ if args.due == 'today' and due <= today:
155
+ filtered.append(t)
156
+ elif args.due == 'week' and due <= today + timedelta(days=7):
157
+ filtered.append(t)
158
+ elif args.due == 'overdue' and due < today:
159
+ filtered.append(t)
160
+ tasks = filtered
161
+
162
+ if not tasks:
163
+ print("No tasks found matching criteria.")
164
+ return
165
+
166
+ print(f"Found {len(tasks)} task(s):\n")
167
+ for task in tasks:
168
+ print(format_task(task))
169
+ print()
170
+
171
+
172
+ def cmd_update(args):
173
+ """Update an existing task."""
174
+ data = {}
175
+
176
+ if args.title:
177
+ data['title'] = args.title
178
+ if args.description:
179
+ data['description'] = args.description
180
+ if args.status:
181
+ data['status'] = args.status
182
+ if args.priority:
183
+ data['priority'] = args.priority
184
+ if args.due:
185
+ data['dueDate'] = parse_date(args.due)
186
+ if args.tags:
187
+ data['tags'] = [t.strip() for t in args.tags.split(',')]
188
+ if args.project:
189
+ project = find_project(args.project)
190
+ if project:
191
+ data['projectId'] = project['id']
192
+
193
+ if not data:
194
+ error("No updates specified")
195
+ sys.exit(1)
196
+
197
+ task_id = find_task_by_id(args.id)
198
+ if not task_id:
199
+ error(f"Task not found: {args.id}")
200
+ sys.exit(1)
201
+
202
+ ok, result = put(f'/tasks/{task_id}', data)
203
+ if ok:
204
+ success(f"Updated task: {result['title']}", result)
205
+ else:
206
+ error(f"Failed to update task: {result}")
207
+ sys.exit(1)
208
+
209
+
210
+ def cmd_done(args):
211
+ """Mark a task as done."""
212
+ task_id = find_task_by_id(args.id_or_search)
213
+
214
+ if not task_id:
215
+ ok, tasks = get('/tasks', {'search': args.id_or_search})
216
+ if ok and tasks:
217
+ incomplete = [t for t in tasks if t.get('status') != 'done']
218
+ if len(incomplete) == 1:
219
+ task_id = incomplete[0]['id']
220
+ elif len(incomplete) > 1:
221
+ print(f"Multiple tasks match '{args.id_or_search}':", file=sys.stderr)
222
+ for t in incomplete[:5]:
223
+ print(f" - {t['title']} (ID: {t['id'][:8]})", file=sys.stderr)
224
+ error("Please be more specific or use task ID")
225
+ sys.exit(1)
226
+
227
+ if not task_id:
228
+ error(f"Task not found: {args.id_or_search}")
229
+ sys.exit(1)
230
+
231
+ ok, result = put(f'/tasks/{task_id}', {'status': 'done'})
232
+ if ok:
233
+ success(f"Completed: {result['title']}")
234
+ else:
235
+ error(f"Failed to complete task: {result}")
236
+ sys.exit(1)
237
+
238
+
239
+ def cmd_delete(args):
240
+ """Delete a task (soft delete)."""
241
+ task_id = find_task_by_id(args.id)
242
+ if not task_id:
243
+ error(f"Task not found: {args.id}")
244
+ sys.exit(1)
245
+
246
+ ok, result = delete(f'/tasks/{task_id}')
247
+ if ok:
248
+ success(f"Deleted task: {args.id}")
249
+ else:
250
+ error(f"Failed to delete task: {result}")
251
+ sys.exit(1)
252
+
253
+
254
+ def main():
255
+ parser = argparse.ArgumentParser(description='Task Management Skill')
256
+ subparsers = parser.add_subparsers(dest='command', required=True)
257
+
258
+ # Create
259
+ create_p = subparsers.add_parser('create', help='Create a new task')
260
+ create_p.add_argument('title', help='Task title')
261
+ create_p.add_argument('--project', '-p', help='Project name')
262
+ create_p.add_argument('--priority', '-P', type=int, choices=[1, 2, 3],
263
+ help='Priority (1=Low, 2=Medium, 3=High)')
264
+ create_p.add_argument('--due', '-d', help='Due date')
265
+ create_p.add_argument('--tags', '-t', help='Comma-separated tags')
266
+ create_p.add_argument('--description', help='Task description')
267
+
268
+ # List
269
+ list_p = subparsers.add_parser('list', help='List tasks')
270
+ list_p.add_argument('--status', '-s',
271
+ choices=['todo', 'in_progress', 'done', 'blocked'])
272
+ list_p.add_argument('--project', '-p', help='Filter by project')
273
+ list_p.add_argument('--search', '-q', help='Search title/description')
274
+ list_p.add_argument('--due', choices=['today', 'week', 'overdue'])
275
+
276
+ # Update
277
+ update_p = subparsers.add_parser('update', help='Update a task')
278
+ update_p.add_argument('id', help='Task ID (prefix)')
279
+ update_p.add_argument('--title', help='New title')
280
+ update_p.add_argument('--description', help='New description')
281
+ update_p.add_argument('--status',
282
+ choices=['todo', 'in_progress', 'done', 'blocked'])
283
+ update_p.add_argument('--priority', type=int, choices=[1, 2, 3])
284
+ update_p.add_argument('--due', help='New due date')
285
+ update_p.add_argument('--tags', help='New tags')
286
+ update_p.add_argument('--project', help='New project')
287
+
288
+ # Done
289
+ done_p = subparsers.add_parser('done', help='Mark task as done')
290
+ done_p.add_argument('id_or_search', help='Task ID or title search')
291
+
292
+ # Delete
293
+ delete_p = subparsers.add_parser('delete', help='Delete a task')
294
+ delete_p.add_argument('id', help='Task ID (prefix)')
295
+
296
+ args = parser.parse_args()
297
+
298
+ commands = {
299
+ 'create': cmd_create,
300
+ 'list': cmd_list,
301
+ 'update': cmd_update,
302
+ 'done': cmd_done,
303
+ 'delete': cmd_delete,
304
+ }
305
+
306
+ commands[args.command](args)
307
+
308
+
309
+ if __name__ == '__main__':
310
+ main()
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Tony Costanzo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,176 @@
1
+ # Cognova
2
+
3
+ Personal knowledge management system with an embedded AI terminal. Built for a unified place to manage notes, tasks, and AI-assisted workflows from any device.
4
+
5
+ > **Warning:** This application gives an AI agent unrestricted access to the host machine via an embedded terminal and the Claude Code CLI. It can read, write, and execute anything. **Do not run this on a personal machine or a server with sensitive data.** Deploy only in a sandboxed, isolated, or airgapped environment. See [Security](#security) for details.
6
+
7
+ ## Features
8
+
9
+ - **File Browser** - Navigate your vault with drag-drop, context menus, search
10
+ - **Markdown Editor** - WYSIWYG editing powered by TipTap via Nuxt UI
11
+ - **Embedded Terminal** - Claude Code CLI in a floating terminal panel
12
+ - **Interactive Chat** - Conversational Claude interface with streaming, tool calls, and session history
13
+ - **Task Management** - Track tasks with status, priority, and project tags
14
+ - **Scheduled Agents** - Cron-based Claude agents with cost tracking and real-time status
15
+ - **Memory Dashboard** - View and manage Claude's memory context
16
+ - **Dashboard** - Overview of recent activity and quick capture
17
+ - **Custom Homepage** - Override the landing page by creating `index.md` in your vault
18
+ - **Public Document Sharing** - Share vault documents via unique link (no auth required)
19
+ - **Hook Events** - Monitor and review Claude Code hook activity
20
+
21
+ ## Tech Stack
22
+
23
+ | Layer | Technology |
24
+ |-------|------------|
25
+ | Framework | [Nuxt 4](https://nuxt.com) |
26
+ | UI | [Nuxt UI v4](https://ui.nuxt.com) |
27
+ | Editor | TipTap (via UEditor) |
28
+ | Terminal | xterm.js + node-pty |
29
+ | Database | PostgreSQL (local Docker or [Neon](https://neon.tech)) |
30
+ | AI | [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) |
31
+
32
+ ## Installation
33
+
34
+ ### Prerequisites
35
+
36
+ - Node.js 20+
37
+ - PostgreSQL (local Docker or hosted like [Neon](https://neon.tech))
38
+ - [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) installed and authenticated
39
+
40
+ ### Install via CLI
41
+
42
+ ```bash
43
+ # Install globally
44
+ npm install -g cognova
45
+
46
+ # Run the interactive setup wizard
47
+ cognova init
48
+ ```
49
+
50
+ The setup wizard will:
51
+ 1. Ask for your vault path (where your markdown files live)
52
+ 2. Configure your database connection (local Docker or Neon)
53
+ 3. Set up authentication secrets
54
+ 4. Install dependencies and build the application
55
+ 5. Start the app via PM2
56
+
57
+ Once running, visit `http://localhost:3000`.
58
+
59
+ ### Managing the App
60
+
61
+ ```bash
62
+ cognova start # Start the app (PM2)
63
+ cognova stop # Stop the app
64
+ cognova restart # Restart the app
65
+ cognova update # Update to the latest version (with automatic rollback)
66
+ cognova doctor # Check health of all components
67
+ cognova reset # Regenerate configuration files
68
+ ```
69
+
70
+ ### Default Admin User
71
+
72
+ On first startup with an empty database, a default admin user is created:
73
+ - Email: `admin@example.com`
74
+ - Password: `changeme123`
75
+
76
+ Customize via `ADMIN_EMAIL` and `ADMIN_PASSWORD` in your `.env` file.
77
+
78
+ ## Environment Variables
79
+
80
+ | Variable | Required | Description |
81
+ |----------|----------|-------------|
82
+ | `VAULT_PATH` | Yes | Path to your markdown vault |
83
+ | `DATABASE_URL` | No | PostgreSQL URL (defaults to local Docker) |
84
+ | `BETTER_AUTH_SECRET` | Yes | Secret key for session encryption (generate with `openssl rand -base64 32`) |
85
+ | `BETTER_AUTH_URL` | Yes | Base URL of your app (e.g., `http://localhost:3000`) |
86
+ | `ADMIN_EMAIL` | No | Default admin email (default: `admin@example.com`) |
87
+ | `ADMIN_PASSWORD` | No | Default admin password (default: `changeme123`) |
88
+ | `ADMIN_NAME` | No | Default admin display name (default: `Admin`) |
89
+
90
+ ## Security
91
+
92
+ Cognova gives an AI agent (Claude Code) and any authenticated user **full, unrestricted access** to the host machine. This includes:
93
+
94
+ - Arbitrary command execution via the embedded terminal
95
+ - File system read/write through the vault mount and shell
96
+ - Network access from the host (API calls, outbound connections)
97
+ - Access to any credentials or secrets present on the machine
98
+
99
+ ### Deployment Guidelines
100
+
101
+ - **Never run on a personal machine** — use a dedicated VM, container, or cloud instance
102
+ - **Isolate the environment** — sandbox or airgap the host so a compromised session can't reach sensitive infrastructure
103
+ - **Never expose directly to the internet** — always put a reverse proxy with TLS in front (Nginx, Traefik, Cloudflare Access, Tailscale, etc.)
104
+ - **Limit blast radius** — don't store SSH keys, cloud credentials, or production secrets on the same machine
105
+ - **Review agent activity** — use the Hook Events dashboard to monitor what Claude Code is doing
106
+
107
+ ## Development
108
+
109
+ ### Setup
110
+
111
+ ```bash
112
+ git clone https://github.com/patrity/cognova.git
113
+ cd cognova
114
+ pnpm install
115
+ cp .env.example .env
116
+ # Edit .env with your VAULT_PATH and database config
117
+ ```
118
+
119
+ ### Local PostgreSQL
120
+
121
+ Docker Compose is used to run a local PostgreSQL instance for development:
122
+
123
+ ```bash
124
+ # Start postgres
125
+ pnpm db:up
126
+
127
+ # Run dev server
128
+ pnpm dev
129
+
130
+ # Stop postgres when done
131
+ pnpm db:down
132
+ ```
133
+
134
+ Alternatively, point `DATABASE_URL` at any PostgreSQL instance (hosted Neon, local install, etc.).
135
+
136
+ ### Build
137
+
138
+ ```bash
139
+ pnpm build
140
+ node .output/server/index.mjs
141
+ ```
142
+
143
+ ## Project Structure
144
+
145
+ ```
146
+ cognova/
147
+ ├── app/
148
+ │ ├── components/ # Vue components
149
+ │ ├── composables/ # Shared logic
150
+ │ ├── layouts/ # Dashboard, auth, view layouts
151
+ │ └── pages/ # Route pages
152
+ ├── server/
153
+ │ ├── api/ # REST endpoints
154
+ │ ├── routes/ # WebSocket handlers
155
+ │ ├── services/ # Agent executor, cron scheduler
156
+ │ └── db/ # Drizzle schema + migrations
157
+ ├── cli/ # CLI installer (cognova init/update/start/stop)
158
+ ├── shared/ # Shared types and utilities
159
+ ├── Claude/ # Claude Code skills, hooks, & config
160
+ └── docs/ # Architecture docs
161
+ ```
162
+
163
+ ## Documentation
164
+
165
+ | Document | Description |
166
+ |----------|-------------|
167
+ | [architecture.md](./docs/architecture.md) | System design and components |
168
+ | [ui-wireframes.md](./docs/ui-wireframes.md) | Interface layouts |
169
+
170
+ ## Contributing
171
+
172
+ Contributions are welcome! See [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines.
173
+
174
+ ## License
175
+
176
+ MIT - see [LICENSE](./LICENSE)
@@ -0,0 +1,8 @@
1
+ export default defineAppConfig({
2
+ ui: {
3
+ colors: {
4
+ primary: 'orange',
5
+ neutral: 'stone'
6
+ }
7
+ }
8
+ })
package/app/app.vue ADDED
@@ -0,0 +1,39 @@
1
+ <script setup lang="ts">
2
+ const colorMode = useColorMode()
3
+
4
+ const color = computed(() => colorMode.value === 'dark' ? '#1b1718' : 'white')
5
+
6
+ useHead({
7
+ meta: [
8
+ { charset: 'utf-8' },
9
+ { name: 'viewport', content: 'width=device-width, initial-scale=1' },
10
+ { key: 'theme-color', name: 'theme-color', content: color }
11
+ ],
12
+ link: [
13
+ { rel: 'icon', href: '/favicon.ico' }
14
+ ],
15
+ htmlAttrs: {
16
+ lang: 'en'
17
+ }
18
+ })
19
+
20
+ const title = 'Cognova'
21
+ const description = 'A personal knowledge management system powered by Claude Code.'
22
+
23
+ useSeoMeta({
24
+ title,
25
+ description,
26
+ ogTitle: title,
27
+ ogDescription: description
28
+ })
29
+ </script>
30
+
31
+ <template>
32
+ <UApp>
33
+ <NuxtLoadingIndicator />
34
+
35
+ <NuxtLayout>
36
+ <NuxtPage />
37
+ </NuxtLayout>
38
+ </UApp>
39
+ </template>
@@ -0,0 +1,10 @@
1
+ @import "tailwindcss";
2
+ @import "@nuxt/ui";
3
+
4
+ @theme {
5
+ --font-sans: 'Outfit', sans-serif;
6
+ }
7
+
8
+ :root {
9
+ --ui-radius: 0.375rem;
10
+ }
@@ -0,0 +1,40 @@
1
+ <template>
2
+ <svg
3
+ width="1020"
4
+ height="200"
5
+ viewBox="0 0 1020 200"
6
+ fill="none"
7
+ xmlns="http://www.w3.org/2000/svg"
8
+ >
9
+ <path
10
+ d="M377 200C379.16 200 381 198.209 381 196V103C381 103 386 112 395 127L434 194C435.785 197.74 439.744 200 443 200H470V50H443C441.202 50 439 51.4941 439 54V148L421 116L385 55C383.248 51.8912 379.479 50 376 50H350V200H377Z"
11
+ fill="currentColor"
12
+ />
13
+ <path
14
+ d="M726 92H739C742.314 92 745 89.3137 745 86V60H773V92H800V116H773V159C773 169.5 778.057 174 787 174H800V200H783C759.948 200 745 185.071 745 160V116H726V92Z"
15
+ fill="currentColor"
16
+ />
17
+ <path
18
+ d="M591 92V154C591 168.004 585.742 179.809 578 188C570.258 196.191 559.566 200 545 200C530.434 200 518.742 196.191 511 188C503.389 179.809 498 168.004 498 154V92H514C517.412 92 520.769 92.622 523 95C525.231 97.2459 526 98.5652 526 102V154C526 162.059 526.457 167.037 530 171C533.543 174.831 537.914 176 545 176C552.217 176 555.457 174.831 559 171C562.543 167.037 563 162.059 563 154V102C563 98.5652 563.769 96.378 566 94C567.96 91.9107 570.028 91.9599 573 92C573.411 92.0055 574.586 92 575 92H591Z"
19
+ fill="currentColor"
20
+ />
21
+ <path
22
+ d="M676 144L710 92H684C680.723 92 677.812 93.1758 676 96L660 120L645 97C643.188 94.1758 639.277 92 636 92H611L645 143L608 200H634C637.25 200 640.182 196.787 642 194L660 167L679 195C680.818 197.787 683.75 200 687 200H713L676 144Z"
23
+ fill="currentColor"
24
+ />
25
+ <path
26
+ d="M168 200H279C282.542 200 285.932 198.756 289 197C292.068 195.244 295.23 193.041 297 190C298.77 186.959 300.002 183.51 300 179.999C299.998 176.488 298.773 173.04 297 170.001L222 41C220.23 37.96 218.067 35.7552 215 34C211.933 32.2448 207.542 31 204 31C200.458 31 197.067 32.2448 194 34C190.933 35.7552 188.77 37.96 187 41L168 74L130 9.99764C128.228 6.95784 126.068 3.75491 123 2C119.932 0.245087 116.542 0 113 0C109.458 0 106.068 0.245087 103 2C99.9323 3.75491 96.7717 6.95784 95 9.99764L2 170.001C0.226979 173.04 0.00154312 176.488 1.90993e-06 179.999C-0.0015393 183.51 0.229648 186.959 2 190C3.77035 193.04 6.93245 195.244 10 197C13.0675 198.756 16.4578 200 20 200H90C117.737 200 137.925 187.558 152 164L186 105L204 74L259 168H186L168 200ZM89 168H40L113 42L150 105L125.491 147.725C116.144 163.01 105.488 168 89 168Z"
27
+ fill="var(--ui-primary)"
28
+ />
29
+ <path
30
+ d="M958 60.0001H938C933.524 60.0001 929.926 59.9395 927 63C924.074 65.8905 925 67.5792 925 72V141C925 151.372 923.648 156.899 919 162C914.352 166.931 908.468 169 899 169C889.705 169 882.648 166.931 878 162C873.352 156.899 873 151.372 873 141V72.0001C873 67.5793 872.926 65.8906 870 63.0001C867.074 59.9396 863.476 60.0001 859 60.0001H840V141C840 159.023 845.016 173.458 855 184C865.156 194.542 879.893 200 899 200C918.107 200 932.844 194.542 943 184C953.156 173.458 958 159.023 958 141V60.0001Z"
31
+ fill="var(--ui-primary)"
32
+ />
33
+ <path
34
+ fill-rule="evenodd"
35
+ clip-rule="evenodd"
36
+ d="M1000 60.0233L1020 60V77L1020 128V156.007L1020 181L1020 189.004C1020 192.938 1019.98 194.429 1017 197.001C1014.02 199.725 1009.56 200 1005 200H986.001V181.006L986 130.012V70.0215C986 66.1576 986.016 64.5494 989 62.023C991.819 59.6358 995.437 60.0233 1000 60.0233Z"
37
+ fill="var(--ui-primary)"
38
+ />
39
+ </svg>
40
+ </template>