@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,389 @@
1
+ # J.A.R.V.I.S. Configuration System
2
+
3
+ Type-safe YAML configuration management for Project J.A.R.V.I.S.
4
+
5
+ ## Overview
6
+
7
+ The configuration system provides:
8
+ - **Type-Safe Config**: Full TypeScript types for all configuration options
9
+ - **YAML Format**: Human-readable YAML files
10
+ - **Deep Merging**: Loaded config merges with defaults for missing values
11
+ - **Path Expansion**: Automatic `~` (tilde) expansion for home directory
12
+ - **Default Values**: Sensible defaults for all settings
13
+
14
+ ## Configuration File
15
+
16
+ Default location: `~/.jarvis/config.yaml`
17
+
18
+ See `config.example.yaml` in the project root for a full example.
19
+
20
+ ## Usage
21
+
22
+ ### Loading Configuration
23
+
24
+ ```typescript
25
+ import { loadConfig } from './config/index.ts';
26
+
27
+ // Load from default location (~/.jarvis/config.yaml)
28
+ const config = await loadConfig();
29
+
30
+ // Load from custom path
31
+ const config = await loadConfig('/path/to/config.yaml');
32
+
33
+ // Config is type-safe
34
+ console.log(config.daemon.port); // number
35
+ console.log(config.llm.primary); // string
36
+ console.log(config.personality.core_traits); // string[]
37
+ ```
38
+
39
+ ### Saving Configuration
40
+
41
+ ```typescript
42
+ import { saveConfig } from './config/index.ts';
43
+
44
+ // Modify config
45
+ config.daemon.port = 8888;
46
+ config.llm.primary = 'openai';
47
+
48
+ // Save to default location
49
+ await saveConfig(config);
50
+
51
+ // Save to custom path
52
+ await saveConfig(config, '/path/to/config.yaml');
53
+ ```
54
+
55
+ ### Using Default Config
56
+
57
+ ```typescript
58
+ import { DEFAULT_CONFIG } from './config/index.ts';
59
+
60
+ // Get a fresh copy of defaults
61
+ const config = { ...DEFAULT_CONFIG };
62
+ ```
63
+
64
+ ## Configuration Schema
65
+
66
+ ### `daemon`
67
+
68
+ Daemon server configuration.
69
+
70
+ ```typescript
71
+ daemon: {
72
+ port: number; // WebSocket server port (default: 7777)
73
+ data_dir: string; // Data directory path (default: ~/.jarvis)
74
+ db_path: string; // SQLite database path (default: ~/.jarvis/jarvis.db)
75
+ }
76
+ ```
77
+
78
+ ### `llm`
79
+
80
+ LLM provider configuration.
81
+
82
+ ```typescript
83
+ llm: {
84
+ primary: string; // Primary provider name ('anthropic' | 'openai' | 'ollama')
85
+ fallback: string[]; // Fallback providers in order
86
+
87
+ // Anthropic (Claude) configuration
88
+ anthropic?: {
89
+ api_key: string;
90
+ model?: string; // Default: claude-sonnet-4-5-20250929
91
+ };
92
+
93
+ // OpenAI (GPT) configuration
94
+ openai?: {
95
+ api_key: string;
96
+ model?: string; // Default: gpt-4o
97
+ base_url?: string; // Optional OpenAI-compatible API base URL
98
+ };
99
+
100
+ // Ollama (local models) configuration
101
+ ollama?: {
102
+ base_url?: string; // Default: http://localhost:11434
103
+ model?: string; // Default: llama3
104
+ };
105
+ }
106
+ ```
107
+
108
+ ### `personality`
109
+
110
+ Core personality traits that guide J.A.R.V.I.S. behavior.
111
+
112
+ ```typescript
113
+ personality: {
114
+ core_traits: string[]; // Array of personality traits
115
+ }
116
+ ```
117
+
118
+ Default traits:
119
+ - `loyal`: Committed to serving the user
120
+ - `efficient`: Optimizes for speed and resource usage
121
+ - `proactive`: Anticipates needs and suggests improvements
122
+ - `respectful`: Maintains professional boundaries
123
+ - `adaptive`: Learns from interactions and adjusts behavior
124
+
125
+ ### `authority`
126
+
127
+ Authority and permission levels.
128
+
129
+ ```typescript
130
+ authority: {
131
+ default_level: number; // Default authority level (0-5)
132
+ }
133
+ ```
134
+
135
+ Authority levels:
136
+ - **0**: No permission - ask for everything
137
+ - **1**: Read-only operations
138
+ - **2**: Safe modifications (non-destructive)
139
+ - **3**: Standard operations (default)
140
+ - **4**: System changes (config, settings)
141
+ - **5**: Full control (destructive operations)
142
+
143
+ ### `active_role`
144
+
145
+ Active role configuration file name.
146
+
147
+ ```typescript
148
+ active_role: string; // Role file name (e.g., 'default', 'developer', 'assistant')
149
+ ```
150
+
151
+ Roles are loaded from `./roles/` directory.
152
+
153
+ ## Default Configuration
154
+
155
+ ```yaml
156
+ daemon:
157
+ port: 7777
158
+ data_dir: "~/.jarvis"
159
+ db_path: "~/.jarvis/jarvis.db"
160
+
161
+ llm:
162
+ primary: "anthropic"
163
+ fallback:
164
+ - "openai"
165
+ - "ollama"
166
+ anthropic:
167
+ api_key: ""
168
+ model: "claude-sonnet-4-5-20250929"
169
+ openai:
170
+ api_key: ""
171
+ model: "gpt-4o"
172
+ # base_url: "https://your-openai-compatible-api-base"
173
+ ollama:
174
+ base_url: "http://localhost:11434"
175
+ model: "llama3"
176
+
177
+ personality:
178
+ core_traits:
179
+ - "loyal"
180
+ - "efficient"
181
+ - "proactive"
182
+ - "respectful"
183
+ - "adaptive"
184
+
185
+ authority:
186
+ default_level: 3
187
+
188
+ active_role: "default"
189
+ ```
190
+
191
+ ## Example Usage
192
+
193
+ ### Initializing LLM Providers from Config
194
+
195
+ ```typescript
196
+ import { loadConfig } from './config/index.ts';
197
+ import { LLMManager, AnthropicProvider, OpenAIProvider, OllamaProvider } from './llm/index.ts';
198
+
199
+ const config = await loadConfig();
200
+ const manager = new LLMManager();
201
+
202
+ // Register providers based on config
203
+ if (config.llm.anthropic?.api_key) {
204
+ const anthropic = new AnthropicProvider(
205
+ config.llm.anthropic.api_key,
206
+ config.llm.anthropic.model
207
+ );
208
+ manager.registerProvider(anthropic);
209
+ }
210
+
211
+ if (config.llm.openai?.api_key) {
212
+ const openai = new OpenAIProvider(
213
+ config.llm.openai.api_key,
214
+ config.llm.openai.model
215
+ );
216
+ manager.registerProvider(openai);
217
+ }
218
+
219
+ if (config.llm.ollama) {
220
+ const ollama = new OllamaProvider(
221
+ config.llm.ollama.base_url,
222
+ config.llm.ollama.model
223
+ );
224
+ manager.registerProvider(ollama);
225
+ }
226
+
227
+ manager.setPrimary(config.llm.primary);
228
+ manager.setFallbackChain(config.llm.fallback);
229
+ ```
230
+
231
+ ### Setting Up Data Directory
232
+
233
+ ```typescript
234
+ import { mkdir } from 'node:fs/promises';
235
+ import { loadConfig } from './config/index.ts';
236
+
237
+ const config = await loadConfig();
238
+
239
+ // Ensure data directory exists
240
+ await mkdir(config.daemon.data_dir, { recursive: true });
241
+
242
+ console.log(`Data directory: ${config.daemon.data_dir}`);
243
+ console.log(`Database path: ${config.daemon.db_path}`);
244
+ ```
245
+
246
+ ### Dynamic Configuration Updates
247
+
248
+ ```typescript
249
+ import { loadConfig, saveConfig } from './config/index.ts';
250
+
251
+ // Load current config
252
+ const config = await loadConfig();
253
+
254
+ // Update settings
255
+ config.daemon.port = 8888;
256
+ config.llm.primary = 'openai';
257
+ config.personality.core_traits.push('humorous');
258
+
259
+ // Save changes
260
+ await saveConfig(config);
261
+
262
+ console.log('Configuration updated!');
263
+ ```
264
+
265
+ ## Setup Instructions
266
+
267
+ 1. **Copy Example Config**:
268
+ ```bash
269
+ mkdir -p ~/.jarvis
270
+ cp config.example.yaml ~/.jarvis/config.yaml
271
+ ```
272
+
273
+ 2. **Edit Configuration**:
274
+ ```bash
275
+ nano ~/.jarvis/config.yaml
276
+ ```
277
+
278
+ 3. **Add API Keys**:
279
+ - Get Anthropic API key from: https://console.anthropic.com/
280
+ - Get OpenAI API key from: https://platform.openai.com/
281
+ - Install Ollama from: https://ollama.ai/
282
+
283
+ 4. **Test Configuration**:
284
+ ```typescript
285
+ import { loadConfig } from './config/index.ts';
286
+ const config = await loadConfig();
287
+ console.log('Config loaded:', config);
288
+ ```
289
+
290
+ ## Environment Variables
291
+
292
+ You can also use environment variables for sensitive values:
293
+
294
+ ```yaml
295
+ llm:
296
+ anthropic:
297
+ api_key: "${ANTHROPIC_API_KEY}"
298
+ openai:
299
+ api_key: "${OPENAI_API_KEY}"
300
+ ```
301
+
302
+ Then set in your shell:
303
+ ```bash
304
+ export ANTHROPIC_API_KEY="sk-ant-..."
305
+ export OPENAI_API_KEY="sk-..."
306
+ ```
307
+
308
+ Note: The loader doesn't currently support env var substitution, but you can implement it with:
309
+
310
+ ```typescript
311
+ function substituteEnvVars(value: string): string {
312
+ return value.replace(/\$\{(\w+)\}/g, (_, key) => process.env[key] || '');
313
+ }
314
+ ```
315
+
316
+ ## Migration Guide
317
+
318
+ If you have an existing config and the schema changes:
319
+
320
+ 1. The deep merge ensures new fields get default values
321
+ 2. Old fields remain unchanged
322
+ 3. You can manually add new fields from `config.example.yaml`
323
+
324
+ ## Best Practices
325
+
326
+ 1. **Never commit API keys**: Add `~/.jarvis/config.yaml` to `.gitignore`
327
+ 2. **Use environment variables**: For CI/CD and production deployments
328
+ 3. **Keep backups**: Copy config before major changes
329
+ 4. **Validate on load**: Check that required API keys are present
330
+ 5. **Document custom settings**: Add comments to your config YAML
331
+
332
+ ## Type Safety
333
+
334
+ The configuration is fully typed:
335
+
336
+ ```typescript
337
+ import type { JarvisConfig } from './config/index.ts';
338
+
339
+ function validateConfig(config: JarvisConfig): boolean {
340
+ // TypeScript ensures all required fields exist
341
+ if (config.daemon.port < 1024 || config.daemon.port > 65535) {
342
+ return false;
343
+ }
344
+
345
+ if (config.authority.default_level < 0 || config.authority.default_level > 5) {
346
+ return false;
347
+ }
348
+
349
+ return true;
350
+ }
351
+ ```
352
+
353
+ ## Extending Configuration
354
+
355
+ To add new configuration sections:
356
+
357
+ 1. **Update Types** (`src/config/types.ts`):
358
+ ```typescript
359
+ export type JarvisConfig = {
360
+ // ... existing fields
361
+ new_section: {
362
+ setting1: string;
363
+ setting2: number;
364
+ };
365
+ };
366
+
367
+ export const DEFAULT_CONFIG: JarvisConfig = {
368
+ // ... existing defaults
369
+ new_section: {
370
+ setting1: 'default_value',
371
+ setting2: 42,
372
+ },
373
+ };
374
+ ```
375
+
376
+ 2. **Update Example** (`config.example.yaml`):
377
+ ```yaml
378
+ new_section:
379
+ setting1: "default_value"
380
+ setting2: 42
381
+ ```
382
+
383
+ 3. **Use in Code**:
384
+ ```typescript
385
+ const config = await loadConfig();
386
+ console.log(config.new_section.setting1);
387
+ ```
388
+
389
+ The deep merge ensures existing configs get new defaults automatically.
@@ -0,0 +1,6 @@
1
+ // Config types
2
+ export type { JarvisConfig } from './types.ts';
3
+ export { DEFAULT_CONFIG } from './types.ts';
4
+
5
+ // Config loader
6
+ export { loadConfig, saveConfig } from './loader.ts';
@@ -0,0 +1,183 @@
1
+ import { test, expect, describe, beforeEach, afterEach } from 'bun:test';
2
+ import { loadConfig, saveConfig } from './loader.ts';
3
+ import { DEFAULT_CONFIG } from './types.ts';
4
+ import { existsSync } from 'node:fs';
5
+ import { unlink } from 'node:fs/promises';
6
+ import { join, isAbsolute } from 'node:path';
7
+
8
+ const TEST_CONFIG_PATH = '/tmp/jarvis-test-config.yaml';
9
+
10
+ describe('Config Loader', () => {
11
+ afterEach(async () => {
12
+ // Clean up test config file
13
+ if (existsSync(TEST_CONFIG_PATH)) {
14
+ await unlink(TEST_CONFIG_PATH);
15
+ }
16
+ });
17
+
18
+ test('returns default config when file does not exist', async () => {
19
+ const config = await loadConfig('/tmp/nonexistent-config.yaml');
20
+ // Paths should be tilde-expanded, but all other fields match defaults
21
+ expect(config.daemon.port).toBe(DEFAULT_CONFIG.daemon.port);
22
+ expect(config.daemon.data_dir).not.toContain('~');
23
+ expect(config.daemon.db_path).not.toContain('~');
24
+ expect(config.llm).toEqual(DEFAULT_CONFIG.llm);
25
+ expect(config.personality).toEqual(DEFAULT_CONFIG.personality);
26
+ expect(config.authority).toEqual(DEFAULT_CONFIG.authority);
27
+ expect(config.active_role).toBe(DEFAULT_CONFIG.active_role);
28
+ });
29
+
30
+ test('can save and load config', async () => {
31
+ const testConfig = structuredClone(DEFAULT_CONFIG);
32
+ testConfig.daemon.port = 9999;
33
+ testConfig.llm.primary = 'openai';
34
+ testConfig.dashboard = { password_hash: '$2b$test-hash' };
35
+
36
+ await saveConfig(testConfig, TEST_CONFIG_PATH);
37
+ expect(existsSync(TEST_CONFIG_PATH)).toBe(true);
38
+
39
+ const loaded = await loadConfig(TEST_CONFIG_PATH);
40
+ expect(loaded.daemon.port).toBe(9999);
41
+ expect(loaded.llm.primary).toBe('openai');
42
+ expect(loaded.dashboard?.password_hash).toBe('$2b$test-hash');
43
+ });
44
+
45
+ test('deep merges partial config with defaults', async () => {
46
+ // Save a partial config (only some fields)
47
+ const partialYaml = `
48
+ daemon:
49
+ port: 8888
50
+
51
+ llm:
52
+ primary: "openai"
53
+ `;
54
+
55
+ await Bun.write(TEST_CONFIG_PATH, partialYaml);
56
+
57
+ const loaded = await loadConfig(TEST_CONFIG_PATH);
58
+
59
+ // Should have our custom values
60
+ expect(loaded.daemon.port).toBe(8888);
61
+ expect(loaded.llm.primary).toBe('openai');
62
+
63
+ // Should have defaults for missing values (paths are tilde-expanded)
64
+ expect(loaded.daemon.data_dir).not.toContain('~');
65
+ expect(loaded.personality.core_traits).toEqual(DEFAULT_CONFIG.personality.core_traits);
66
+ expect(loaded.authority.default_level).toBe(DEFAULT_CONFIG.authority.default_level);
67
+ });
68
+
69
+ test('preserves all config sections', async () => {
70
+ await saveConfig(DEFAULT_CONFIG, TEST_CONFIG_PATH);
71
+ const loaded = await loadConfig(TEST_CONFIG_PATH);
72
+
73
+ expect(loaded.daemon).toBeDefined();
74
+ expect(loaded.llm).toBeDefined();
75
+ expect(loaded.personality).toBeDefined();
76
+ expect(loaded.authority).toBeDefined();
77
+ expect(loaded.active_role).toBeDefined();
78
+ });
79
+ });
80
+
81
+ describe('Default Config', () => {
82
+ test('has all required fields', () => {
83
+ expect(DEFAULT_CONFIG.daemon).toBeDefined();
84
+ expect(DEFAULT_CONFIG.daemon.port).toBe(3142);
85
+ expect(DEFAULT_CONFIG.daemon.data_dir).toBe('~/.jarvis');
86
+ expect(DEFAULT_CONFIG.daemon.db_path).toBe('~/.jarvis/jarvis.db');
87
+
88
+ expect(DEFAULT_CONFIG.llm).toBeDefined();
89
+ expect(DEFAULT_CONFIG.llm.primary).toBe('anthropic');
90
+ expect(DEFAULT_CONFIG.llm.fallback).toEqual(['openai', 'ollama']);
91
+
92
+ expect(DEFAULT_CONFIG.personality).toBeDefined();
93
+ expect(DEFAULT_CONFIG.personality.core_traits).toBeInstanceOf(Array);
94
+
95
+ expect(DEFAULT_CONFIG.authority).toBeDefined();
96
+ expect(DEFAULT_CONFIG.authority.default_level).toBe(3);
97
+
98
+ expect(DEFAULT_CONFIG.active_role).toBe('personal-assistant');
99
+ });
100
+
101
+ test('has correct personality traits', () => {
102
+ const traits = DEFAULT_CONFIG.personality.core_traits;
103
+ expect(traits).toContain('loyal');
104
+ expect(traits).toContain('efficient');
105
+ expect(traits).toContain('proactive');
106
+ expect(traits).toContain('respectful');
107
+ expect(traits).toContain('adaptive');
108
+ });
109
+
110
+ test('has correct LLM defaults', () => {
111
+ expect(DEFAULT_CONFIG.llm.anthropic?.model).toBe('claude-sonnet-4-6');
112
+ expect(DEFAULT_CONFIG.llm.openai?.model).toBe('gpt-5.4');
113
+ expect(DEFAULT_CONFIG.llm.openai?.base_url).toBeUndefined();
114
+ expect(DEFAULT_CONFIG.llm.gemini?.model).toBe('gemini-3-flash-preview');
115
+ expect(DEFAULT_CONFIG.llm.ollama?.model).toBe('llama3');
116
+ expect(DEFAULT_CONFIG.llm.ollama?.base_url).toBe('http://localhost:11434');
117
+ expect(DEFAULT_CONFIG.dashboard?.password_hash).toBeUndefined();
118
+ });
119
+ });
120
+
121
+ describe('Config Parse Errors', () => {
122
+ afterEach(async () => {
123
+ if (existsSync(TEST_CONFIG_PATH)) {
124
+ await unlink(TEST_CONFIG_PATH);
125
+ }
126
+ });
127
+
128
+ test('throws on malformed YAML when file exists', async () => {
129
+ const badYaml = `
130
+ daemon:
131
+ port: 3142
132
+ bad_indent: true
133
+ this is: not: valid
134
+ `;
135
+ await Bun.write(TEST_CONFIG_PATH, badYaml);
136
+
137
+ expect(loadConfig(TEST_CONFIG_PATH)).rejects.toThrow();
138
+ });
139
+
140
+ test('uses defaults when file does not exist (no throw)', async () => {
141
+ const config = await loadConfig('/tmp/jarvis-definitely-not-here.yaml');
142
+ expect(config.daemon.port).toBe(DEFAULT_CONFIG.daemon.port);
143
+ expect(config.daemon.data_dir).not.toContain('~');
144
+ expect(config.daemon.db_path).not.toContain('~');
145
+ });
146
+
147
+ test('expands tildes in parsed config', async () => {
148
+ const yamlWithTilde = `
149
+ daemon:
150
+ data_dir: "~/.jarvis"
151
+ db_path: "~/.jarvis/jarvis.db"
152
+ `;
153
+ await Bun.write(TEST_CONFIG_PATH, yamlWithTilde);
154
+
155
+ const config = await loadConfig(TEST_CONFIG_PATH);
156
+ expect(config.daemon.data_dir).not.toContain('~');
157
+ expect(config.daemon.db_path).not.toContain('~');
158
+ expect(isAbsolute(config.daemon.data_dir)).toBe(true);
159
+ expect(isAbsolute(config.daemon.db_path)).toBe(true);
160
+ });
161
+ });
162
+
163
+ describe('Path Expansion', () => {
164
+ test('expands tilde in paths', async () => {
165
+ const config = await loadConfig();
166
+
167
+ // Should expand ~ to home directory
168
+ expect(config.daemon.data_dir).not.toContain('~');
169
+ expect(config.daemon.db_path).not.toContain('~');
170
+ });
171
+
172
+ test('preserves non-tilde paths', async () => {
173
+ const testConfig = { ...DEFAULT_CONFIG };
174
+ testConfig.daemon.data_dir = '/absolute/path';
175
+ testConfig.daemon.db_path = '/absolute/db.db';
176
+
177
+ await saveConfig(testConfig, TEST_CONFIG_PATH);
178
+ const loaded = await loadConfig(TEST_CONFIG_PATH);
179
+
180
+ expect(loaded.daemon.data_dir).toBe('/absolute/path');
181
+ expect(loaded.daemon.db_path).toBe('/absolute/db.db');
182
+ });
183
+ });