@shykaruu/jarvis-brain 0.4.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 (330) hide show
  1. package/LICENSE +153 -0
  2. package/README.md +428 -0
  3. package/bin/jarvis.ts +449 -0
  4. package/package.json +79 -0
  5. package/roles/activity-observer.yaml +60 -0
  6. package/roles/ceo-founder.yaml +144 -0
  7. package/roles/chief-of-staff.yaml +158 -0
  8. package/roles/dev-lead.yaml +182 -0
  9. package/roles/executive-assistant.yaml +77 -0
  10. package/roles/marketing-director.yaml +168 -0
  11. package/roles/personal-assistant.yaml +266 -0
  12. package/roles/research-specialist.yaml +60 -0
  13. package/roles/specialists/content-writer.yaml +53 -0
  14. package/roles/specialists/customer-support.yaml +57 -0
  15. package/roles/specialists/data-analyst.yaml +57 -0
  16. package/roles/specialists/financial-analyst.yaml +56 -0
  17. package/roles/specialists/hr-specialist.yaml +55 -0
  18. package/roles/specialists/legal-advisor.yaml +58 -0
  19. package/roles/specialists/marketing-strategist.yaml +56 -0
  20. package/roles/specialists/project-coordinator.yaml +55 -0
  21. package/roles/specialists/research-analyst.yaml +58 -0
  22. package/roles/specialists/software-engineer.yaml +57 -0
  23. package/roles/specialists/system-administrator.yaml +57 -0
  24. package/roles/system-admin.yaml +76 -0
  25. package/scripts/ensure-bun.cjs +16 -0
  26. package/src/actions/README.md +421 -0
  27. package/src/actions/app-control/desktop-controller.test.ts +26 -0
  28. package/src/actions/app-control/desktop-controller.ts +438 -0
  29. package/src/actions/app-control/interface.ts +64 -0
  30. package/src/actions/app-control/linux.ts +273 -0
  31. package/src/actions/app-control/macos.ts +54 -0
  32. package/src/actions/app-control/sidecar-launcher.test.ts +23 -0
  33. package/src/actions/app-control/sidecar-launcher.ts +286 -0
  34. package/src/actions/app-control/windows.ts +44 -0
  35. package/src/actions/browser/cdp.ts +138 -0
  36. package/src/actions/browser/chrome-launcher.ts +261 -0
  37. package/src/actions/browser/session.ts +506 -0
  38. package/src/actions/browser/stealth.ts +49 -0
  39. package/src/actions/index.ts +20 -0
  40. package/src/actions/terminal/executor.ts +157 -0
  41. package/src/actions/terminal/wsl-bridge.ts +126 -0
  42. package/src/actions/test.ts +93 -0
  43. package/src/actions/tools/agents.ts +363 -0
  44. package/src/actions/tools/builtin.ts +950 -0
  45. package/src/actions/tools/commitments.ts +192 -0
  46. package/src/actions/tools/content.ts +217 -0
  47. package/src/actions/tools/delegate.ts +147 -0
  48. package/src/actions/tools/desktop.test.ts +55 -0
  49. package/src/actions/tools/desktop.ts +305 -0
  50. package/src/actions/tools/documents.ts +169 -0
  51. package/src/actions/tools/goals.ts +376 -0
  52. package/src/actions/tools/local-tools-guard.ts +31 -0
  53. package/src/actions/tools/registry.ts +173 -0
  54. package/src/actions/tools/research.ts +111 -0
  55. package/src/actions/tools/sidecar-list.ts +57 -0
  56. package/src/actions/tools/sidecar-route.ts +105 -0
  57. package/src/actions/tools/workflows.ts +216 -0
  58. package/src/agents/agent.ts +132 -0
  59. package/src/agents/delegation.ts +107 -0
  60. package/src/agents/hierarchy.ts +113 -0
  61. package/src/agents/index.ts +19 -0
  62. package/src/agents/messaging.ts +125 -0
  63. package/src/agents/orchestrator.ts +592 -0
  64. package/src/agents/role-discovery.ts +61 -0
  65. package/src/agents/sub-agent-runner.ts +309 -0
  66. package/src/agents/task-manager.ts +151 -0
  67. package/src/authority/approval-delivery.ts +59 -0
  68. package/src/authority/approval.ts +196 -0
  69. package/src/authority/audit.ts +158 -0
  70. package/src/authority/authority.test.ts +519 -0
  71. package/src/authority/deferred-executor.ts +103 -0
  72. package/src/authority/emergency.ts +66 -0
  73. package/src/authority/engine.ts +301 -0
  74. package/src/authority/index.ts +12 -0
  75. package/src/authority/learning.ts +111 -0
  76. package/src/authority/tool-action-map.ts +74 -0
  77. package/src/awareness/analytics.ts +466 -0
  78. package/src/awareness/awareness.test.ts +332 -0
  79. package/src/awareness/capture-engine.ts +305 -0
  80. package/src/awareness/context-graph.ts +130 -0
  81. package/src/awareness/context-tracker.ts +349 -0
  82. package/src/awareness/index.ts +25 -0
  83. package/src/awareness/intelligence.ts +321 -0
  84. package/src/awareness/ocr-engine.ts +88 -0
  85. package/src/awareness/service.ts +528 -0
  86. package/src/awareness/struggle-detector.ts +342 -0
  87. package/src/awareness/suggestion-engine.ts +476 -0
  88. package/src/awareness/types.ts +201 -0
  89. package/src/cli/autostart.ts +417 -0
  90. package/src/cli/deps.ts +449 -0
  91. package/src/cli/doctor.ts +238 -0
  92. package/src/cli/helpers.ts +401 -0
  93. package/src/cli/onboard.ts +827 -0
  94. package/src/cli/uninstall.test.ts +37 -0
  95. package/src/cli/uninstall.ts +202 -0
  96. package/src/comms/README.md +329 -0
  97. package/src/comms/auth-error.html +48 -0
  98. package/src/comms/channels/discord.ts +228 -0
  99. package/src/comms/channels/signal.ts +56 -0
  100. package/src/comms/channels/telegram.ts +316 -0
  101. package/src/comms/channels/whatsapp.ts +60 -0
  102. package/src/comms/channels.test.ts +173 -0
  103. package/src/comms/dashboard-auth.ts +75 -0
  104. package/src/comms/desktop-notify.ts +114 -0
  105. package/src/comms/example.ts +129 -0
  106. package/src/comms/index.ts +129 -0
  107. package/src/comms/streaming.ts +149 -0
  108. package/src/comms/voice.test.ts +504 -0
  109. package/src/comms/voice.ts +341 -0
  110. package/src/comms/websocket.test.ts +409 -0
  111. package/src/comms/websocket.ts +669 -0
  112. package/src/config/README.md +389 -0
  113. package/src/config/index.ts +6 -0
  114. package/src/config/loader.test.ts +183 -0
  115. package/src/config/loader.ts +148 -0
  116. package/src/config/types.ts +293 -0
  117. package/src/daemon/README.md +232 -0
  118. package/src/daemon/agent-service-interface.ts +9 -0
  119. package/src/daemon/agent-service.ts +667 -0
  120. package/src/daemon/api-routes.ts +3067 -0
  121. package/src/daemon/background-agent-service.ts +396 -0
  122. package/src/daemon/background-agent.test.ts +78 -0
  123. package/src/daemon/channel-service.ts +201 -0
  124. package/src/daemon/commitment-executor.ts +297 -0
  125. package/src/daemon/dashboard-auth.test.ts +170 -0
  126. package/src/daemon/event-classifier.ts +239 -0
  127. package/src/daemon/event-coalescer.ts +123 -0
  128. package/src/daemon/event-reactor.ts +214 -0
  129. package/src/daemon/flock.c +7 -0
  130. package/src/daemon/health.ts +220 -0
  131. package/src/daemon/index.ts +1070 -0
  132. package/src/daemon/llm-settings.test.ts +78 -0
  133. package/src/daemon/llm-settings.ts +450 -0
  134. package/src/daemon/observer-service.ts +150 -0
  135. package/src/daemon/pid.test.ts +283 -0
  136. package/src/daemon/pid.ts +224 -0
  137. package/src/daemon/research-queue.ts +155 -0
  138. package/src/daemon/services.ts +175 -0
  139. package/src/daemon/ws-service.ts +926 -0
  140. package/src/global.d.ts +4 -0
  141. package/src/goals/accountability.ts +240 -0
  142. package/src/goals/awareness-bridge.ts +185 -0
  143. package/src/goals/estimator.ts +185 -0
  144. package/src/goals/events.ts +28 -0
  145. package/src/goals/goals.test.ts +400 -0
  146. package/src/goals/integration.test.ts +329 -0
  147. package/src/goals/nl-builder.test.ts +220 -0
  148. package/src/goals/nl-builder.ts +256 -0
  149. package/src/goals/rhythm.test.ts +177 -0
  150. package/src/goals/rhythm.ts +275 -0
  151. package/src/goals/service.test.ts +135 -0
  152. package/src/goals/service.ts +407 -0
  153. package/src/goals/types.ts +106 -0
  154. package/src/goals/workflow-bridge.ts +96 -0
  155. package/src/integrations/google-api.ts +134 -0
  156. package/src/integrations/google-auth.ts +175 -0
  157. package/src/llm/README.md +291 -0
  158. package/src/llm/anthropic.ts +400 -0
  159. package/src/llm/gemini.ts +380 -0
  160. package/src/llm/groq.ts +406 -0
  161. package/src/llm/history.ts +147 -0
  162. package/src/llm/index.ts +21 -0
  163. package/src/llm/manager.ts +226 -0
  164. package/src/llm/ollama.ts +316 -0
  165. package/src/llm/openai.ts +411 -0
  166. package/src/llm/openrouter.ts +390 -0
  167. package/src/llm/provider.test.ts +487 -0
  168. package/src/llm/provider.ts +61 -0
  169. package/src/llm/test.ts +88 -0
  170. package/src/observers/README.md +278 -0
  171. package/src/observers/calendar.ts +113 -0
  172. package/src/observers/clipboard.ts +136 -0
  173. package/src/observers/email.ts +109 -0
  174. package/src/observers/example.ts +58 -0
  175. package/src/observers/file-watcher.ts +124 -0
  176. package/src/observers/index.ts +159 -0
  177. package/src/observers/notifications.ts +197 -0
  178. package/src/observers/observers.test.ts +203 -0
  179. package/src/observers/processes.ts +225 -0
  180. package/src/personality/README.md +61 -0
  181. package/src/personality/adapter.ts +196 -0
  182. package/src/personality/index.ts +20 -0
  183. package/src/personality/learner.ts +209 -0
  184. package/src/personality/model.ts +132 -0
  185. package/src/personality/personality.test.ts +236 -0
  186. package/src/roles/README.md +252 -0
  187. package/src/roles/authority.ts +120 -0
  188. package/src/roles/example-usage.ts +198 -0
  189. package/src/roles/index.ts +42 -0
  190. package/src/roles/loader.ts +143 -0
  191. package/src/roles/prompt-builder.ts +218 -0
  192. package/src/roles/test-multi.ts +102 -0
  193. package/src/roles/test-role.yaml +77 -0
  194. package/src/roles/test-utils.ts +93 -0
  195. package/src/roles/test.ts +106 -0
  196. package/src/roles/tool-guide.ts +195 -0
  197. package/src/roles/types.ts +36 -0
  198. package/src/roles/utils.ts +200 -0
  199. package/src/scripts/google-setup.ts +168 -0
  200. package/src/sidecar/connection.ts +179 -0
  201. package/src/sidecar/index.ts +6 -0
  202. package/src/sidecar/manager.ts +542 -0
  203. package/src/sidecar/protocol.ts +85 -0
  204. package/src/sidecar/rpc.ts +161 -0
  205. package/src/sidecar/scheduler.ts +136 -0
  206. package/src/sidecar/types.ts +112 -0
  207. package/src/sidecar/validator.ts +144 -0
  208. package/src/sites/builder-tools.ts +215 -0
  209. package/src/sites/dev-server-manager.ts +286 -0
  210. package/src/sites/fixtures/security-test-site/.jarvis-project.json +6 -0
  211. package/src/sites/fixtures/security-test-site/Makefile +15 -0
  212. package/src/sites/fixtures/security-test-site/README.md +18 -0
  213. package/src/sites/fixtures/security-test-site/index.html +12 -0
  214. package/src/sites/fixtures/security-test-site/index.ts +16 -0
  215. package/src/sites/fixtures/security-test-site/package.json +13 -0
  216. package/src/sites/fixtures/security-test-site/src/app.tsx +780 -0
  217. package/src/sites/fixtures/security-test-site/tsconfig.json +10 -0
  218. package/src/sites/git-manager.ts +240 -0
  219. package/src/sites/github-manager.ts +355 -0
  220. package/src/sites/index.ts +25 -0
  221. package/src/sites/project-manager.ts +389 -0
  222. package/src/sites/proxy.ts +133 -0
  223. package/src/sites/service.ts +136 -0
  224. package/src/sites/templates.ts +169 -0
  225. package/src/sites/types.ts +89 -0
  226. package/src/user/profile-followup.test.ts +84 -0
  227. package/src/user/profile-followup.ts +185 -0
  228. package/src/user/profile.ts +224 -0
  229. package/src/vault/README.md +110 -0
  230. package/src/vault/awareness.ts +341 -0
  231. package/src/vault/commitments.ts +299 -0
  232. package/src/vault/content-pipeline.ts +270 -0
  233. package/src/vault/conversations.ts +173 -0
  234. package/src/vault/dashboard-sessions.ts +44 -0
  235. package/src/vault/documents.ts +130 -0
  236. package/src/vault/entities.ts +185 -0
  237. package/src/vault/extractor.test.ts +356 -0
  238. package/src/vault/extractor.ts +345 -0
  239. package/src/vault/facts.ts +190 -0
  240. package/src/vault/goals.ts +477 -0
  241. package/src/vault/index.ts +87 -0
  242. package/src/vault/keychain.ts +99 -0
  243. package/src/vault/observations.ts +115 -0
  244. package/src/vault/relationships.ts +178 -0
  245. package/src/vault/retrieval.test.ts +139 -0
  246. package/src/vault/retrieval.ts +258 -0
  247. package/src/vault/schema.ts +709 -0
  248. package/src/vault/settings.ts +38 -0
  249. package/src/vault/user-profile.test.ts +113 -0
  250. package/src/vault/user-profile.ts +176 -0
  251. package/src/vault/vectors.ts +92 -0
  252. package/src/vault/webapp-template-seeds.ts +116 -0
  253. package/src/vault/webapp-templates.ts +244 -0
  254. package/src/vault/workflows.ts +403 -0
  255. package/src/workflows/auto-suggest.ts +290 -0
  256. package/src/workflows/engine.ts +366 -0
  257. package/src/workflows/events.ts +24 -0
  258. package/src/workflows/executor.ts +207 -0
  259. package/src/workflows/nl-builder.ts +198 -0
  260. package/src/workflows/nodes/actions/agent-task.ts +73 -0
  261. package/src/workflows/nodes/actions/calendar-action.ts +85 -0
  262. package/src/workflows/nodes/actions/code-execution.ts +73 -0
  263. package/src/workflows/nodes/actions/discord.ts +77 -0
  264. package/src/workflows/nodes/actions/file-write.ts +73 -0
  265. package/src/workflows/nodes/actions/gmail.ts +69 -0
  266. package/src/workflows/nodes/actions/http-request.ts +117 -0
  267. package/src/workflows/nodes/actions/notification.ts +85 -0
  268. package/src/workflows/nodes/actions/run-tool.ts +55 -0
  269. package/src/workflows/nodes/actions/send-message.ts +82 -0
  270. package/src/workflows/nodes/actions/shell-command.ts +76 -0
  271. package/src/workflows/nodes/actions/telegram.ts +60 -0
  272. package/src/workflows/nodes/builtin.ts +119 -0
  273. package/src/workflows/nodes/error/error-handler.ts +37 -0
  274. package/src/workflows/nodes/error/fallback.ts +47 -0
  275. package/src/workflows/nodes/error/retry.ts +82 -0
  276. package/src/workflows/nodes/logic/delay.ts +42 -0
  277. package/src/workflows/nodes/logic/if-else.ts +41 -0
  278. package/src/workflows/nodes/logic/loop.ts +90 -0
  279. package/src/workflows/nodes/logic/merge.ts +38 -0
  280. package/src/workflows/nodes/logic/race.ts +40 -0
  281. package/src/workflows/nodes/logic/switch.ts +59 -0
  282. package/src/workflows/nodes/logic/template-render.ts +53 -0
  283. package/src/workflows/nodes/logic/variable-get.ts +37 -0
  284. package/src/workflows/nodes/logic/variable-set.ts +59 -0
  285. package/src/workflows/nodes/registry.ts +99 -0
  286. package/src/workflows/nodes/transform/aggregate.ts +99 -0
  287. package/src/workflows/nodes/transform/csv-parse.ts +70 -0
  288. package/src/workflows/nodes/transform/json-parse.ts +63 -0
  289. package/src/workflows/nodes/transform/map-filter.ts +84 -0
  290. package/src/workflows/nodes/transform/regex-match.ts +89 -0
  291. package/src/workflows/nodes/triggers/calendar.ts +33 -0
  292. package/src/workflows/nodes/triggers/clipboard.ts +32 -0
  293. package/src/workflows/nodes/triggers/cron.ts +40 -0
  294. package/src/workflows/nodes/triggers/email.ts +40 -0
  295. package/src/workflows/nodes/triggers/file-change.ts +45 -0
  296. package/src/workflows/nodes/triggers/git.ts +46 -0
  297. package/src/workflows/nodes/triggers/manual.ts +23 -0
  298. package/src/workflows/nodes/triggers/poll.ts +81 -0
  299. package/src/workflows/nodes/triggers/process.ts +44 -0
  300. package/src/workflows/nodes/triggers/screen-event.ts +37 -0
  301. package/src/workflows/nodes/triggers/webhook.ts +39 -0
  302. package/src/workflows/safe-eval.ts +139 -0
  303. package/src/workflows/template.ts +118 -0
  304. package/src/workflows/triggers/cron.ts +311 -0
  305. package/src/workflows/triggers/manager.ts +285 -0
  306. package/src/workflows/triggers/observer-bridge.ts +172 -0
  307. package/src/workflows/triggers/poller.ts +201 -0
  308. package/src/workflows/triggers/screen-condition.ts +218 -0
  309. package/src/workflows/triggers/triggers.test.ts +740 -0
  310. package/src/workflows/triggers/webhook.ts +191 -0
  311. package/src/workflows/types.ts +133 -0
  312. package/src/workflows/variables.ts +72 -0
  313. package/src/workflows/workflows.test.ts +383 -0
  314. package/src/workflows/yaml.ts +104 -0
  315. package/ui/dist/index-3gr23jt9.js +112614 -0
  316. package/ui/dist/index-9vmj8127.css +14239 -0
  317. package/ui/dist/index-hy9pc1gm.js +112873 -0
  318. package/ui/dist/index-j2ep5d1w.js +112374 -0
  319. package/ui/dist/index-jt00vjqs.js +112858 -0
  320. package/ui/dist/index-k9ymx5qb.js +112374 -0
  321. package/ui/dist/index.html +16 -0
  322. package/ui/public/audio/pcm-capture-processor.js +11 -0
  323. package/ui/public/openwakeword/models/embedding_model.onnx +0 -0
  324. package/ui/public/openwakeword/models/hey_jarvis_v0.1.onnx +0 -0
  325. package/ui/public/openwakeword/models/melspectrogram.onnx +0 -0
  326. package/ui/public/openwakeword/models/silero_vad.onnx +0 -0
  327. package/ui/public/ort/ort-wasm-simd-threaded.jsep.mjs +106 -0
  328. package/ui/public/ort/ort-wasm-simd-threaded.jsep.wasm +0 -0
  329. package/ui/public/ort/ort-wasm-simd-threaded.mjs +59 -0
  330. package/ui/public/ort/ort-wasm-simd-threaded.wasm +0 -0
@@ -0,0 +1,224 @@
1
+ export type UserProfileQuestionId =
2
+ | 'preferred_name'
3
+ | 'pronouns'
4
+ | 'location_timezone'
5
+ | 'work_role'
6
+ | 'interests'
7
+ | 'current_projects'
8
+ | 'goals_next_90_days'
9
+ | 'communication_preferences'
10
+ | 'pet_peeves'
11
+ | 'routines_constraints'
12
+ | 'tools_stack'
13
+ | 'important_people'
14
+ | 'anything_else';
15
+
16
+ export type UserProfileQuestion = {
17
+ id: UserProfileQuestionId;
18
+ step: number;
19
+ step_title: string;
20
+ label: string;
21
+ prompt: string;
22
+ description: string;
23
+ placeholder?: string;
24
+ multiline?: boolean;
25
+ };
26
+
27
+ export type UserProfileRecord = {
28
+ version: 1;
29
+ answers: Partial<Record<UserProfileQuestionId, string>>;
30
+ created_at: number;
31
+ updated_at: number;
32
+ completed_at: number | null;
33
+ };
34
+
35
+ export const USER_PROFILE_SETTING_KEY = 'user.profile.v1';
36
+
37
+ export const USER_PROFILE_QUESTIONS: UserProfileQuestion[] = [
38
+ {
39
+ id: 'preferred_name',
40
+ step: 1,
41
+ step_title: 'Identity',
42
+ label: 'Preferred Name',
43
+ prompt: 'What should JARVIS call you?',
44
+ description: 'Use the name you actually want the assistant to use in conversation.',
45
+ placeholder: 'e.g. Alex',
46
+ },
47
+ {
48
+ id: 'pronouns',
49
+ step: 1,
50
+ step_title: 'Identity',
51
+ label: 'Pronouns',
52
+ prompt: 'What pronouns do you want JARVIS to use, if any?',
53
+ description: 'Optional, but useful for natural and respectful replies.',
54
+ placeholder: 'e.g. she/her, he/him, they/them',
55
+ },
56
+ {
57
+ id: 'location_timezone',
58
+ step: 1,
59
+ step_title: 'Identity',
60
+ label: 'Location / Timezone',
61
+ prompt: 'What location or timezone should JARVIS keep in mind?',
62
+ description: 'This helps with scheduling, recommendations, and time references.',
63
+ placeholder: 'e.g. Miami, FL / America/New_York',
64
+ },
65
+ {
66
+ id: 'work_role',
67
+ step: 1,
68
+ step_title: 'Identity',
69
+ label: 'Work / Role',
70
+ prompt: 'What do you do, or what roles do you usually operate in?',
71
+ description: 'Career, studies, side hustles, and the kinds of responsibilities you handle.',
72
+ placeholder: 'e.g. founder, student, engineer, creator',
73
+ multiline: true,
74
+ },
75
+ {
76
+ id: 'interests',
77
+ step: 2,
78
+ step_title: 'Interests',
79
+ label: 'Interests',
80
+ prompt: 'What are you genuinely interested in?',
81
+ description: 'Topics, hobbies, communities, subjects, and rabbit holes you care about.',
82
+ placeholder: 'e.g. AI, fitness, cars, anime, startups',
83
+ multiline: true,
84
+ },
85
+ {
86
+ id: 'current_projects',
87
+ step: 2,
88
+ step_title: 'Interests',
89
+ label: 'Current Projects',
90
+ prompt: 'What are you actively working on right now?',
91
+ description: 'Projects, businesses, classes, routines, or personal efforts already in motion.',
92
+ placeholder: 'What is already on your plate?',
93
+ multiline: true,
94
+ },
95
+ {
96
+ id: 'goals_next_90_days',
97
+ step: 2,
98
+ step_title: 'Interests',
99
+ label: 'Goals',
100
+ prompt: 'What do you want to accomplish over the next 30 to 90 days?',
101
+ description: 'Short-term outcomes that JARVIS should optimize around.',
102
+ placeholder: 'What should JARVIS help push forward?',
103
+ multiline: true,
104
+ },
105
+ {
106
+ id: 'communication_preferences',
107
+ step: 3,
108
+ step_title: 'Working Style',
109
+ label: 'Communication Preferences',
110
+ prompt: 'How do you want JARVIS to communicate with you?',
111
+ description: 'Tone, directness, detail level, structure, reminders, and how much pushback you want.',
112
+ placeholder: 'e.g. blunt, concise, actionable, no fluff',
113
+ multiline: true,
114
+ },
115
+ {
116
+ id: 'pet_peeves',
117
+ step: 3,
118
+ step_title: 'Working Style',
119
+ label: 'Pet Peeves',
120
+ prompt: 'What annoys you or wastes your time?',
121
+ description: 'Patterns to avoid in planning, writing, or collaboration.',
122
+ placeholder: 'What should JARVIS not do?',
123
+ multiline: true,
124
+ },
125
+ {
126
+ id: 'routines_constraints',
127
+ step: 3,
128
+ step_title: 'Working Style',
129
+ label: 'Routines & Constraints',
130
+ prompt: 'What routines, limits, or constraints should JARVIS know?',
131
+ description: 'Schedule constraints, health habits, budget limits, availability, or boundaries.',
132
+ placeholder: 'Anything that should shape reminders or recommendations',
133
+ multiline: true,
134
+ },
135
+ {
136
+ id: 'tools_stack',
137
+ step: 4,
138
+ step_title: 'Context',
139
+ label: 'Tools & Stack',
140
+ prompt: 'What tools, apps, or technical stack do you use most?',
141
+ description: 'Software, devices, languages, frameworks, and workflows JARVIS should assume.',
142
+ placeholder: 'e.g. GitHub, Bun, React, Notion, Telegram, Windows',
143
+ multiline: true,
144
+ },
145
+ {
146
+ id: 'important_people',
147
+ step: 4,
148
+ step_title: 'Context',
149
+ label: 'Important People',
150
+ prompt: 'Who are the important people, teams, or audiences around you?',
151
+ description: 'Managers, cofounders, clients, family, friends, or communities that matter in your context.',
152
+ placeholder: 'Who should JARVIS keep in mind?',
153
+ multiline: true,
154
+ },
155
+ {
156
+ id: 'anything_else',
157
+ step: 4,
158
+ step_title: 'Context',
159
+ label: 'Anything Else',
160
+ prompt: 'What else should JARVIS know to be useful from day one?',
161
+ description: 'Any extra context that does not fit the earlier prompts.',
162
+ placeholder: 'Anything important you want carried forward',
163
+ multiline: true,
164
+ },
165
+ ];
166
+
167
+ export function createEmptyUserProfile(): UserProfileRecord {
168
+ const now = Date.now();
169
+ return {
170
+ version: 1,
171
+ answers: {},
172
+ created_at: now,
173
+ updated_at: now,
174
+ completed_at: null,
175
+ };
176
+ }
177
+
178
+ export function normalizeUserProfileAnswers(
179
+ input: Record<string, unknown>,
180
+ ): Partial<Record<UserProfileQuestionId, string>> {
181
+ const answers: Partial<Record<UserProfileQuestionId, string>> = {};
182
+
183
+ for (const question of USER_PROFILE_QUESTIONS) {
184
+ const raw = input[question.id];
185
+ if (typeof raw !== 'string') continue;
186
+ const value = raw.trim();
187
+ if (!value) continue;
188
+ answers[question.id] = value;
189
+ }
190
+
191
+ return answers;
192
+ }
193
+
194
+ export function countAnsweredUserProfileQuestions(profile: UserProfileRecord | null): number {
195
+ if (!profile) return 0;
196
+ return USER_PROFILE_QUESTIONS.filter((question) => Boolean(profile.answers[question.id]?.trim())).length;
197
+ }
198
+
199
+ export function hasUserProfile(profile: UserProfileRecord | null): boolean {
200
+ return countAnsweredUserProfileQuestions(profile) > 0;
201
+ }
202
+
203
+ export function formatUserProfileForPrompt(profile: UserProfileRecord | null): string | undefined {
204
+ if (!profile) return undefined;
205
+
206
+ const lines: string[] = [];
207
+ for (const question of USER_PROFILE_QUESTIONS) {
208
+ const answer = profile.answers[question.id]?.trim();
209
+ if (!answer) continue;
210
+ lines.push(`- ${question.label}: |`);
211
+ lines.push(indentPromptValue(answer));
212
+ }
213
+
214
+ if (lines.length === 0) return undefined;
215
+ return lines.join('\n');
216
+ }
217
+
218
+ function indentPromptValue(value: string): string {
219
+ return value
220
+ .replace(/\r\n/g, '\n')
221
+ .split('\n')
222
+ .map((line) => ` ${line}`)
223
+ .join('\n');
224
+ }
@@ -0,0 +1,110 @@
1
+ # Vault Module
2
+
3
+ Knowledge graph storage and extraction system for J.A.R.V.I.S.
4
+
5
+ ## Modules
6
+
7
+ - **`schema.ts`**: Database schema and initialization
8
+ - **`entities.ts`**: Entity CRUD operations
9
+ - **`facts.ts`**: Fact storage and queries
10
+ - **`relationships.ts`**: Relationship management
11
+ - **`commitments.ts`**: Promise and task tracking
12
+ - **`observations.ts`**: Raw event storage
13
+ - **`vectors.ts`**: Embedding storage for semantic search
14
+ - **`extractor.ts`**: LLM-powered knowledge extraction
15
+ - **`index.ts`**: Public API exports
16
+
17
+ ## Quick Start
18
+
19
+ ### Initialize Database
20
+
21
+ ```typescript
22
+ import { initDatabase } from '@/vault';
23
+
24
+ initDatabase('./data/jarvis.db');
25
+ ```
26
+
27
+ ### Store Knowledge Manually
28
+
29
+ ```typescript
30
+ import { createEntity, createFact, createRelationship } from '@/vault';
31
+
32
+ // Create entity
33
+ const anna = createEntity('person', 'Anna', {
34
+ role: 'software engineer',
35
+ });
36
+
37
+ // Add fact
38
+ createFact(anna.id, 'birthday_is', 'March 15', {
39
+ confidence: 1.0,
40
+ });
41
+
42
+ // Create relationship
43
+ const google = createEntity('tool', 'Google');
44
+ createRelationship(anna.id, google.id, 'works_at');
45
+ ```
46
+
47
+ ### Extract Knowledge with LLM
48
+
49
+ ```typescript
50
+ import { extractAndStore } from '@/vault';
51
+ import { AnthropicProvider } from '@/llm/anthropic';
52
+
53
+ const llm = new AnthropicProvider(process.env.ANTHROPIC_API_KEY);
54
+
55
+ const result = await extractAndStore(
56
+ "Anna's birthday is March 15th",
57
+ "I'll remember that!",
58
+ llm
59
+ );
60
+ ```
61
+
62
+ ### Query Knowledge
63
+
64
+ ```typescript
65
+ import { findEntities, findFacts, findCommitments } from '@/vault';
66
+
67
+ // Find people
68
+ const people = findEntities({ type: 'person' });
69
+
70
+ // Find facts about Anna
71
+ const facts = findFacts({ subject_id: anna.id });
72
+
73
+ // Find pending commitments
74
+ const pending = findCommitments({ status: 'pending' });
75
+ ```
76
+
77
+ ## Documentation
78
+
79
+ - **Vault Extractor**: [docs/VAULT_EXTRACTOR.md](~/jarvis/docs/VAULT_EXTRACTOR.md)
80
+ - **Entity Types**: person, project, tool, place, concept, event
81
+ - **Commitment Statuses**: pending, active, completed, failed, escalated
82
+
83
+ ## Testing
84
+
85
+ ```bash
86
+ # Test extractor
87
+ bun test src/vault/extractor.test.ts
88
+
89
+ # Test entire vault (if you have other tests)
90
+ bun test src/vault/**/*.test.ts
91
+ ```
92
+
93
+ ## Demo
94
+
95
+ ```bash
96
+ bun run examples/extractor-demo.ts
97
+ ```
98
+
99
+ ## Database Schema
100
+
101
+ SQLite database with the following tables:
102
+ - `entities`: People, projects, tools, places, concepts, events
103
+ - `facts`: Atomic knowledge with confidence scores
104
+ - `relationships`: Typed edges between entities
105
+ - `commitments`: Promises and tasks
106
+ - `observations`: Raw events
107
+ - `vectors`: Embeddings for semantic search
108
+ - `agent_messages`: Inter-agent communication
109
+ - `personality_state`: Personality model storage
110
+ - `conversations`: Conversation tracking
@@ -0,0 +1,341 @@
1
+ /**
2
+ * Vault — Awareness CRUD
3
+ *
4
+ * Database operations for screen_captures, awareness_sessions, and awareness_suggestions tables.
5
+ * Follows the same patterns as observations.ts and commitments.ts.
6
+ */
7
+
8
+ import { getDb, generateId } from './schema.ts';
9
+ import type {
10
+ ScreenCaptureRow,
11
+ SessionRow,
12
+ SuggestionRow,
13
+ SuggestionType,
14
+ AppUsageStat,
15
+ } from '../awareness/types.ts';
16
+
17
+ // ── Screen Captures ──
18
+
19
+ export function createCapture(data: {
20
+ timestamp: number;
21
+ sessionId?: string;
22
+ imagePath?: string;
23
+ thumbnailPath?: string;
24
+ pixelChangePct: number;
25
+ ocrText?: string;
26
+ appName?: string;
27
+ windowTitle?: string;
28
+ url?: string;
29
+ filePath?: string;
30
+ retentionTier?: 'full' | 'key_moment' | 'metadata_only';
31
+ }): ScreenCaptureRow {
32
+ const db = getDb();
33
+ const id = generateId();
34
+ const now = Date.now();
35
+
36
+ db.prepare(`
37
+ INSERT INTO screen_captures
38
+ (id, timestamp, session_id, image_path, thumbnail_path, pixel_change_pct,
39
+ ocr_text, app_name, window_title, url, file_path, retention_tier, created_at)
40
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
41
+ `).run(
42
+ id,
43
+ data.timestamp,
44
+ data.sessionId ?? null,
45
+ data.imagePath ?? null,
46
+ data.thumbnailPath ?? null,
47
+ data.pixelChangePct,
48
+ data.ocrText ?? null,
49
+ data.appName ?? null,
50
+ data.windowTitle ?? null,
51
+ data.url ?? null,
52
+ data.filePath ?? null,
53
+ data.retentionTier ?? 'full',
54
+ now,
55
+ );
56
+
57
+ return {
58
+ id,
59
+ timestamp: data.timestamp,
60
+ session_id: data.sessionId ?? null,
61
+ image_path: data.imagePath ?? null,
62
+ thumbnail_path: data.thumbnailPath ?? null,
63
+ pixel_change_pct: data.pixelChangePct,
64
+ ocr_text: data.ocrText ?? null,
65
+ app_name: data.appName ?? null,
66
+ window_title: data.windowTitle ?? null,
67
+ url: data.url ?? null,
68
+ file_path: data.filePath ?? null,
69
+ retention_tier: data.retentionTier ?? 'full',
70
+ created_at: now,
71
+ };
72
+ }
73
+
74
+ export function getCapture(id: string): ScreenCaptureRow | null {
75
+ const db = getDb();
76
+ return db.prepare('SELECT * FROM screen_captures WHERE id = ?').get(id) as ScreenCaptureRow | null;
77
+ }
78
+
79
+ export function getRecentCaptures(limit: number = 50, appName?: string): ScreenCaptureRow[] {
80
+ const db = getDb();
81
+ if (appName) {
82
+ return db.prepare(
83
+ 'SELECT * FROM screen_captures WHERE app_name = ? ORDER BY timestamp DESC LIMIT ?'
84
+ ).all(appName, limit) as ScreenCaptureRow[];
85
+ }
86
+ return db.prepare(
87
+ 'SELECT * FROM screen_captures ORDER BY timestamp DESC LIMIT ?'
88
+ ).all(limit) as ScreenCaptureRow[];
89
+ }
90
+
91
+ export function getCapturesInRange(startTime: number, endTime: number): ScreenCaptureRow[] {
92
+ const db = getDb();
93
+ return db.prepare(
94
+ 'SELECT * FROM screen_captures WHERE timestamp >= ? AND timestamp <= ? ORDER BY timestamp ASC'
95
+ ).all(startTime, endTime) as ScreenCaptureRow[];
96
+ }
97
+
98
+ export function getAppUsageStats(startTime: number, endTime: number): AppUsageStat[] {
99
+ const db = getDb();
100
+ const rows = db.prepare(`
101
+ SELECT app_name, COUNT(*) as capture_count
102
+ FROM screen_captures
103
+ WHERE timestamp >= ? AND timestamp <= ? AND app_name IS NOT NULL
104
+ GROUP BY app_name
105
+ ORDER BY capture_count DESC
106
+ `).all(startTime, endTime) as Array<{ app_name: string; capture_count: number }>;
107
+
108
+ const totalCaptures = rows.reduce((sum, r) => sum + r.capture_count, 0);
109
+
110
+ return rows.map(r => ({
111
+ app: r.app_name,
112
+ captureCount: r.capture_count,
113
+ minutes: Math.round((r.capture_count * 7) / 60), // ~7s per capture
114
+ percentage: totalCaptures > 0 ? Math.round((r.capture_count / totalCaptures) * 100) : 0,
115
+ }));
116
+ }
117
+
118
+ export function getCaptureCountSince(timestamp: number): number {
119
+ const db = getDb();
120
+ const row = db.prepare(
121
+ 'SELECT COUNT(*) as count FROM screen_captures WHERE timestamp >= ?'
122
+ ).get(timestamp) as { count: number };
123
+ return row.count;
124
+ }
125
+
126
+ export function updateCaptureRetention(id: string, tier: 'full' | 'key_moment' | 'metadata_only'): void {
127
+ const db = getDb();
128
+ db.prepare('UPDATE screen_captures SET retention_tier = ? WHERE id = ?').run(tier, id);
129
+ }
130
+
131
+ export function deleteCapturesBefore(timestamp: number, retentionTier: string): number {
132
+ const db = getDb();
133
+ const result = db.prepare(
134
+ 'DELETE FROM screen_captures WHERE timestamp < ? AND retention_tier = ?'
135
+ ).run(timestamp, retentionTier);
136
+ return result.changes;
137
+ }
138
+
139
+ export function updateCaptureOcrText(id: string, ocrText: string): void {
140
+ const db = getDb();
141
+ db.prepare('UPDATE screen_captures SET ocr_text = ? WHERE id = ?').run(ocrText, id);
142
+ }
143
+
144
+ export function getCapturesForSession(sessionId: string, limit: number = 50): ScreenCaptureRow[] {
145
+ const db = getDb();
146
+ return db.prepare(
147
+ 'SELECT * FROM screen_captures WHERE session_id = ? ORDER BY timestamp DESC LIMIT ?'
148
+ ).all(sessionId, limit) as ScreenCaptureRow[];
149
+ }
150
+
151
+ // ── Awareness Sessions ──
152
+
153
+ export function createSession(data: {
154
+ startedAt: number;
155
+ apps?: string[];
156
+ projectContext?: string;
157
+ }): SessionRow {
158
+ const db = getDb();
159
+ const id = generateId();
160
+ const now = Date.now();
161
+
162
+ db.prepare(`
163
+ INSERT INTO awareness_sessions
164
+ (id, started_at, ended_at, topic, apps, project_context, action_types, entity_links, summary, capture_count, created_at)
165
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
166
+ `).run(
167
+ id,
168
+ data.startedAt,
169
+ null,
170
+ null,
171
+ JSON.stringify(data.apps ?? []),
172
+ data.projectContext ?? null,
173
+ JSON.stringify([]),
174
+ JSON.stringify([]),
175
+ null,
176
+ 0,
177
+ now,
178
+ );
179
+
180
+ return {
181
+ id,
182
+ started_at: data.startedAt,
183
+ ended_at: null,
184
+ topic: null,
185
+ apps: JSON.stringify(data.apps ?? []),
186
+ project_context: data.projectContext ?? null,
187
+ action_types: JSON.stringify([]),
188
+ entity_links: JSON.stringify([]),
189
+ summary: null,
190
+ capture_count: 0,
191
+ created_at: now,
192
+ };
193
+ }
194
+
195
+ export function getSession(id: string): SessionRow | null {
196
+ const db = getDb();
197
+ return db.prepare('SELECT * FROM awareness_sessions WHERE id = ?').get(id) as SessionRow | null;
198
+ }
199
+
200
+ export function updateSession(id: string, updates: Partial<{
201
+ ended_at: number | null;
202
+ topic: string | null;
203
+ apps: string[];
204
+ project_context: string | null;
205
+ action_types: string[];
206
+ entity_links: string[];
207
+ summary: string | null;
208
+ capture_count: number;
209
+ }>): void {
210
+ const db = getDb();
211
+ const setClauses: string[] = [];
212
+ const params: unknown[] = [];
213
+
214
+ if (updates.ended_at !== undefined) { setClauses.push('ended_at = ?'); params.push(updates.ended_at); }
215
+ if (updates.topic !== undefined) { setClauses.push('topic = ?'); params.push(updates.topic); }
216
+ if (updates.apps !== undefined) { setClauses.push('apps = ?'); params.push(JSON.stringify(updates.apps)); }
217
+ if (updates.project_context !== undefined) { setClauses.push('project_context = ?'); params.push(updates.project_context); }
218
+ if (updates.action_types !== undefined) { setClauses.push('action_types = ?'); params.push(JSON.stringify(updates.action_types)); }
219
+ if (updates.entity_links !== undefined) { setClauses.push('entity_links = ?'); params.push(JSON.stringify(updates.entity_links)); }
220
+ if (updates.summary !== undefined) { setClauses.push('summary = ?'); params.push(updates.summary); }
221
+ if (updates.capture_count !== undefined) { setClauses.push('capture_count = ?'); params.push(updates.capture_count); }
222
+
223
+ if (setClauses.length === 0) return;
224
+
225
+ params.push(id);
226
+ db.prepare(`UPDATE awareness_sessions SET ${setClauses.join(', ')} WHERE id = ?`).run(...params as any[]);
227
+ }
228
+
229
+ export function endSession(id: string, summary?: string): void {
230
+ const db = getDb();
231
+ db.prepare(
232
+ 'UPDATE awareness_sessions SET ended_at = ?, summary = ? WHERE id = ?'
233
+ ).run(Date.now(), summary ?? null, id);
234
+ }
235
+
236
+ export function getRecentSessions(limit: number = 20): SessionRow[] {
237
+ const db = getDb();
238
+ return db.prepare(
239
+ 'SELECT * FROM awareness_sessions ORDER BY started_at DESC LIMIT ?'
240
+ ).all(limit) as SessionRow[];
241
+ }
242
+
243
+ export function incrementSessionCaptureCount(id: string): void {
244
+ const db = getDb();
245
+ db.prepare(
246
+ 'UPDATE awareness_sessions SET capture_count = capture_count + 1 WHERE id = ?'
247
+ ).run(id);
248
+ }
249
+
250
+ // ── Awareness Suggestions ──
251
+
252
+ export function createSuggestion(data: {
253
+ type: SuggestionType;
254
+ triggerCaptureId?: string;
255
+ title: string;
256
+ body: string;
257
+ context?: Record<string, unknown>;
258
+ }): SuggestionRow {
259
+ const db = getDb();
260
+ const id = generateId();
261
+ const now = Date.now();
262
+
263
+ db.prepare(`
264
+ INSERT INTO awareness_suggestions
265
+ (id, type, trigger_capture_id, title, body, context, delivered, delivered_at, delivery_channel, dismissed, acted_on, created_at)
266
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
267
+ `).run(
268
+ id,
269
+ data.type,
270
+ data.triggerCaptureId ?? null,
271
+ data.title,
272
+ data.body,
273
+ data.context ? JSON.stringify(data.context) : null,
274
+ 0, null, null, 0, 0,
275
+ now,
276
+ );
277
+
278
+ return {
279
+ id,
280
+ type: data.type,
281
+ trigger_capture_id: data.triggerCaptureId ?? null,
282
+ title: data.title,
283
+ body: data.body,
284
+ context: data.context ? JSON.stringify(data.context) : null,
285
+ delivered: 0,
286
+ delivered_at: null,
287
+ delivery_channel: null,
288
+ dismissed: 0,
289
+ acted_on: 0,
290
+ created_at: now,
291
+ };
292
+ }
293
+
294
+ export function markSuggestionDelivered(id: string, channel: string): void {
295
+ const db = getDb();
296
+ db.prepare(
297
+ 'UPDATE awareness_suggestions SET delivered = 1, delivered_at = ?, delivery_channel = ? WHERE id = ?'
298
+ ).run(Date.now(), channel, id);
299
+ }
300
+
301
+ export function markSuggestionDismissed(id: string): void {
302
+ const db = getDb();
303
+ db.prepare('UPDATE awareness_suggestions SET dismissed = 1 WHERE id = ?').run(id);
304
+ }
305
+
306
+ export function markSuggestionActedOn(id: string): void {
307
+ const db = getDb();
308
+ db.prepare('UPDATE awareness_suggestions SET acted_on = 1 WHERE id = ?').run(id);
309
+ }
310
+
311
+ export function getRecentSuggestions(limit: number = 20, type?: SuggestionType): SuggestionRow[] {
312
+ const db = getDb();
313
+ if (type) {
314
+ return db.prepare(
315
+ 'SELECT * FROM awareness_suggestions WHERE type = ? ORDER BY created_at DESC LIMIT ?'
316
+ ).all(type, limit) as SuggestionRow[];
317
+ }
318
+ return db.prepare(
319
+ 'SELECT * FROM awareness_suggestions ORDER BY created_at DESC LIMIT ?'
320
+ ).all(limit) as SuggestionRow[];
321
+ }
322
+
323
+ export function getSuggestionCountSince(timestamp: number): number {
324
+ const db = getDb();
325
+ const row = db.prepare(
326
+ 'SELECT COUNT(*) as count FROM awareness_suggestions WHERE created_at >= ?'
327
+ ).get(timestamp) as { count: number };
328
+ return row.count;
329
+ }
330
+
331
+ export function getSuggestionStats(startTime: number, endTime: number): { total: number; actedOn: number } {
332
+ const db = getDb();
333
+ const row = db.prepare(`
334
+ SELECT
335
+ COUNT(*) as total,
336
+ SUM(CASE WHEN acted_on = 1 THEN 1 ELSE 0 END) as acted_on
337
+ FROM awareness_suggestions
338
+ WHERE created_at >= ? AND created_at <= ?
339
+ `).get(startTime, endTime) as { total: number; acted_on: number };
340
+ return { total: row.total, actedOn: row.acted_on ?? 0 };
341
+ }