@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,225 @@
1
+ /**
2
+ * ProcessMonitor - Monitors running processes
3
+ *
4
+ * Polls the system process list at regular intervals and detects when processes
5
+ * start or terminate. Emits events for process lifecycle changes.
6
+ */
7
+
8
+ import type { Observer, ObserverEvent, ObserverEventHandler } from './index';
9
+
10
+ export type ProcessInfo = {
11
+ pid: number;
12
+ name: string;
13
+ cpu: number;
14
+ memory: number;
15
+ };
16
+
17
+ export class ProcessMonitor implements Observer {
18
+ name = 'processes';
19
+ private interval: Timer | null = null;
20
+ private knownProcesses: Map<number, string> = new Map();
21
+ private handler: ObserverEventHandler | null = null;
22
+ private running = false;
23
+ private pollMs: number;
24
+
25
+ constructor(pollMs: number = 5000) {
26
+ this.pollMs = pollMs;
27
+ }
28
+
29
+ async start(): Promise<void> {
30
+ if (this.running) {
31
+ console.log('[processes] Already running');
32
+ return;
33
+ }
34
+
35
+ console.log(`[processes] Starting process monitoring (polling every ${this.pollMs}ms)...`);
36
+
37
+ // Initialize with current process list
38
+ try {
39
+ const processes = await this.getProcessList();
40
+ for (const proc of processes) {
41
+ this.knownProcesses.set(proc.pid, proc.name);
42
+ }
43
+ console.log(`[processes] Initialized with ${processes.length} processes`);
44
+ } catch (error) {
45
+ console.error('[processes] Failed to get initial process list:', error);
46
+ }
47
+
48
+ // Start polling
49
+ this.interval = setInterval(async () => {
50
+ try {
51
+ const processes = await this.getProcessList();
52
+ const currentPids = new Set<number>();
53
+
54
+ // Check for new processes
55
+ for (const proc of processes) {
56
+ currentPids.add(proc.pid);
57
+
58
+ if (!this.knownProcesses.has(proc.pid)) {
59
+ // New process detected
60
+ this.knownProcesses.set(proc.pid, proc.name);
61
+
62
+ if (this.handler) {
63
+ const event: ObserverEvent = {
64
+ type: 'process_started',
65
+ data: {
66
+ pid: proc.pid,
67
+ name: proc.name,
68
+ cpu: proc.cpu,
69
+ memory: proc.memory,
70
+ },
71
+ timestamp: Date.now(),
72
+ };
73
+
74
+ this.handler(event);
75
+ }
76
+ }
77
+ }
78
+
79
+ // Check for terminated processes
80
+ for (const [pid, name] of this.knownProcesses.entries()) {
81
+ if (!currentPids.has(pid)) {
82
+ // Process terminated
83
+ this.knownProcesses.delete(pid);
84
+
85
+ if (this.handler) {
86
+ const event: ObserverEvent = {
87
+ type: 'process_stopped',
88
+ data: {
89
+ pid,
90
+ name,
91
+ },
92
+ timestamp: Date.now(),
93
+ };
94
+
95
+ this.handler(event);
96
+ }
97
+ }
98
+ }
99
+ } catch (error) {
100
+ console.error('[processes] Failed to monitor processes:', error);
101
+ }
102
+ }, this.pollMs);
103
+
104
+ this.running = true;
105
+ }
106
+
107
+ async stop(): Promise<void> {
108
+ if (!this.running) {
109
+ return;
110
+ }
111
+
112
+ console.log('[processes] Stopping process monitoring...');
113
+
114
+ if (this.interval) {
115
+ clearInterval(this.interval);
116
+ this.interval = null;
117
+ }
118
+
119
+ this.knownProcesses.clear();
120
+ this.running = false;
121
+ }
122
+
123
+ isRunning(): boolean {
124
+ return this.running;
125
+ }
126
+
127
+ onEvent(handler: ObserverEventHandler): void {
128
+ this.handler = handler;
129
+ }
130
+
131
+ /**
132
+ * Get list of running processes
133
+ */
134
+ async getProcessList(): Promise<ProcessInfo[]> {
135
+ const platform = process.platform;
136
+
137
+ try {
138
+ if (platform === 'linux' || platform === 'darwin') {
139
+ // Use ps command for Unix-like systems
140
+ const result = await Bun.$`ps aux --no-headers`.quiet();
141
+ const output = result.stdout.toString();
142
+
143
+ return this.parsePS(output);
144
+ } else if (platform === 'win32') {
145
+ // Use PowerShell for Windows
146
+ const result = await Bun.$`powershell.exe -Command "Get-Process | Select-Object Id,Name,CPU,WorkingSet | ConvertTo-Csv -NoTypeInformation"`.quiet();
147
+ const output = result.stdout.toString();
148
+
149
+ return this.parseWindowsPS(output);
150
+ } else {
151
+ throw new Error(`Unsupported platform: ${platform}`);
152
+ }
153
+ } catch (error) {
154
+ console.error('[processes] Failed to get process list:', error);
155
+ return [];
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Parse output from Unix ps command
161
+ */
162
+ private parsePS(output: string): ProcessInfo[] {
163
+ const processes: ProcessInfo[] = [];
164
+ const lines = output.split('\n').filter(line => line.trim());
165
+
166
+ for (const line of lines) {
167
+ // ps aux format: USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
168
+ const parts = line.trim().split(/\s+/);
169
+
170
+ if (parts.length < 11) {
171
+ continue;
172
+ }
173
+
174
+ const pid = parseInt(parts[1]!, 10);
175
+ const cpu = parseFloat(parts[2]!);
176
+ const memory = parseFloat(parts[3]!);
177
+ const name = parts.slice(10).join(' '); // COMMAND can have spaces
178
+
179
+ if (!isNaN(pid)) {
180
+ processes.push({
181
+ pid,
182
+ name,
183
+ cpu,
184
+ memory,
185
+ });
186
+ }
187
+ }
188
+
189
+ return processes;
190
+ }
191
+
192
+ /**
193
+ * Parse output from Windows PowerShell Get-Process
194
+ */
195
+ private parseWindowsPS(output: string): ProcessInfo[] {
196
+ const processes: ProcessInfo[] = [];
197
+ const lines = output.split('\n').filter(line => line.trim());
198
+
199
+ // Skip header line
200
+ for (let i = 1; i < lines.length; i++) {
201
+ const line = lines[i]!;
202
+ const parts = line.split(',').map(p => p.replace(/"/g, '').trim());
203
+
204
+ if (parts.length < 4) {
205
+ continue;
206
+ }
207
+
208
+ const pid = parseInt(parts[0]!, 10);
209
+ const name: string = parts[1]!;
210
+ const cpu = parseFloat(parts[2]!) || 0;
211
+ const memory = parseFloat(parts[3]!) || 0;
212
+
213
+ if (!isNaN(pid)) {
214
+ processes.push({
215
+ pid,
216
+ name,
217
+ cpu,
218
+ memory,
219
+ });
220
+ }
221
+ }
222
+
223
+ return processes;
224
+ }
225
+ }
@@ -0,0 +1,61 @@
1
+ # Personality Engine
2
+
3
+ An adaptive personality system for J.A.R.V.I.S. that learns user preferences and adapts communication style over time.
4
+
5
+ ## Quick Start
6
+
7
+ ```typescript
8
+ import { initDatabase } from '@/vault/schema';
9
+ import {
10
+ getPersonality,
11
+ savePersonality,
12
+ extractSignals,
13
+ applySignals,
14
+ recordInteraction,
15
+ personalityToPrompt,
16
+ } from '@/personality';
17
+
18
+ // Initialize database
19
+ initDatabase('./data/jarvis.db');
20
+
21
+ // Process a user interaction
22
+ let personality = getPersonality();
23
+ const signals = extractSignals("Keep it brief", "Sure!");
24
+ personality = applySignals(personality, signals);
25
+ personality = recordInteraction(personality);
26
+ savePersonality(personality);
27
+
28
+ // Generate LLM prompt
29
+ const prompt = personalityToPrompt(personality);
30
+ ```
31
+
32
+ ## Modules
33
+
34
+ - **`model.ts`**: Personality state structure and persistence
35
+ - **`learner.ts`**: Signal extraction and learning
36
+ - **`adapter.ts`**: Channel adaptation and prompt generation
37
+ - **`index.ts`**: Public API exports
38
+
39
+ ## Features
40
+
41
+ ✓ Learns from user feedback (verbosity, formality, humor)
42
+ ✓ Detects emoji usage preferences
43
+ ✓ Adapts to different channels (WhatsApp, Email, Terminal)
44
+ ✓ Builds trust over time
45
+ ✓ Generates personality-aware LLM prompts
46
+
47
+ ## Documentation
48
+
49
+ See [docs/PERSONALITY_ENGINE.md](~/jarvis/docs/PERSONALITY_ENGINE.md) for full documentation.
50
+
51
+ ## Testing
52
+
53
+ ```bash
54
+ bun test src/personality/personality.test.ts
55
+ ```
56
+
57
+ ## Demo
58
+
59
+ ```bash
60
+ bun run examples/personality-demo.ts
61
+ ```
@@ -0,0 +1,196 @@
1
+ import type { PersonalityModel } from './model.ts';
2
+
3
+ /**
4
+ * Channel-specific personality defaults
5
+ */
6
+ const CHANNEL_DEFAULTS: Record<string, Partial<PersonalityModel>> = {
7
+ whatsapp: {
8
+ learned_preferences: {
9
+ verbosity: 4,
10
+ formality: 3,
11
+ humor_level: 5,
12
+ emoji_usage: true,
13
+ preferred_format: 'lists',
14
+ },
15
+ },
16
+ telegram: {
17
+ learned_preferences: {
18
+ verbosity: 4,
19
+ formality: 3,
20
+ humor_level: 5,
21
+ emoji_usage: true,
22
+ preferred_format: 'lists',
23
+ },
24
+ },
25
+ email: {
26
+ learned_preferences: {
27
+ verbosity: 7,
28
+ formality: 8,
29
+ humor_level: 2,
30
+ emoji_usage: false,
31
+ preferred_format: 'prose',
32
+ },
33
+ },
34
+ terminal: {
35
+ learned_preferences: {
36
+ verbosity: 5,
37
+ formality: 5,
38
+ humor_level: 3,
39
+ emoji_usage: false,
40
+ preferred_format: 'adaptive',
41
+ },
42
+ },
43
+ websocket: {
44
+ learned_preferences: {
45
+ verbosity: 5,
46
+ formality: 5,
47
+ humor_level: 3,
48
+ emoji_usage: false,
49
+ preferred_format: 'adaptive',
50
+ },
51
+ },
52
+ discord: {
53
+ learned_preferences: {
54
+ verbosity: 4,
55
+ formality: 3,
56
+ humor_level: 5,
57
+ emoji_usage: true,
58
+ preferred_format: 'lists',
59
+ },
60
+ },
61
+ };
62
+
63
+ /**
64
+ * Deep merge helper for personality overrides
65
+ */
66
+ function mergePersonality(
67
+ base: PersonalityModel,
68
+ override: Partial<PersonalityModel>
69
+ ): PersonalityModel {
70
+ return {
71
+ ...base,
72
+ core_traits: override.core_traits ?? base.core_traits,
73
+ learned_preferences: {
74
+ ...base.learned_preferences,
75
+ ...override.learned_preferences,
76
+ },
77
+ relationship: {
78
+ ...base.relationship,
79
+ ...override.relationship,
80
+ },
81
+ channel_overrides: {
82
+ ...base.channel_overrides,
83
+ ...override.channel_overrides,
84
+ },
85
+ };
86
+ }
87
+
88
+ /**
89
+ * Get personality adapted for a specific channel
90
+ */
91
+ export function getChannelPersonality(personality: PersonalityModel, channel: string): PersonalityModel {
92
+ // First, apply channel-specific overrides from stored personality
93
+ let adapted = personality;
94
+ if (personality.channel_overrides[channel]) {
95
+ adapted = mergePersonality(personality, personality.channel_overrides[channel]);
96
+ }
97
+
98
+ // Then, apply default channel adaptations if no stored override exists
99
+ if (!personality.channel_overrides[channel] && CHANNEL_DEFAULTS[channel]) {
100
+ adapted = mergePersonality(adapted, CHANNEL_DEFAULTS[channel]);
101
+ }
102
+
103
+ return adapted;
104
+ }
105
+
106
+ /**
107
+ * Generate personality instructions for the LLM system prompt
108
+ */
109
+ export function personalityToPrompt(personality: PersonalityModel): string {
110
+ const { core_traits, learned_preferences, relationship } = personality;
111
+
112
+ const lines: string[] = ['## Personality'];
113
+
114
+ // Core traits
115
+ if (core_traits.length > 0) {
116
+ lines.push(`Core traits: ${core_traits.join(', ')}`);
117
+ }
118
+
119
+ // Communication style
120
+ const verbosityDesc = getVerbosityDescription(learned_preferences.verbosity);
121
+ const formalityDesc = getFormalityDescription(learned_preferences.formality);
122
+ const humorDesc = getHumorDescription(learned_preferences.humor_level);
123
+
124
+ lines.push(
125
+ `Communication: ${verbosityDesc} verbosity (${learned_preferences.verbosity}/10), ${formalityDesc} formality (${learned_preferences.formality}/10), ${humorDesc} humor`
126
+ );
127
+
128
+ // Format preference
129
+ lines.push(`Format preference: ${learned_preferences.preferred_format}`);
130
+
131
+ // Emoji usage
132
+ if (learned_preferences.emoji_usage) {
133
+ lines.push('Emoji usage: Enabled');
134
+ }
135
+
136
+ // Relationship context
137
+ const daysSinceFirst = Math.floor(
138
+ (Date.now() - relationship.first_interaction) / (1000 * 60 * 60 * 24)
139
+ );
140
+ const trustDesc = getTrustDescription(relationship.trust_level);
141
+
142
+ lines.push(
143
+ `Relationship: ${relationship.message_count} interactions over ${daysSinceFirst} days, ${trustDesc} trust level (${relationship.trust_level}/10)`
144
+ );
145
+
146
+ // Shared references
147
+ if (relationship.shared_references.length > 0) {
148
+ lines.push(`Shared references: ${relationship.shared_references.join(', ')}`);
149
+ }
150
+
151
+ return lines.join('\n');
152
+ }
153
+
154
+ /**
155
+ * Helper: Convert verbosity number to description
156
+ */
157
+ function getVerbosityDescription(level: number): string {
158
+ if (level <= 2) return 'Very brief';
159
+ if (level <= 4) return 'Concise';
160
+ if (level <= 6) return 'Moderate';
161
+ if (level <= 8) return 'Detailed';
162
+ return 'Very detailed';
163
+ }
164
+
165
+ /**
166
+ * Helper: Convert formality number to description
167
+ */
168
+ function getFormalityDescription(level: number): string {
169
+ if (level <= 2) return 'Very casual';
170
+ if (level <= 4) return 'Casual';
171
+ if (level <= 6) return 'Moderate';
172
+ if (level <= 8) return 'Formal';
173
+ return 'Very formal';
174
+ }
175
+
176
+ /**
177
+ * Helper: Convert humor level to description
178
+ */
179
+ function getHumorDescription(level: number): string {
180
+ if (level <= 2) return 'minimal';
181
+ if (level <= 4) return 'light';
182
+ if (level <= 6) return 'moderate';
183
+ if (level <= 8) return 'frequent';
184
+ return 'heavy';
185
+ }
186
+
187
+ /**
188
+ * Helper: Convert trust level to description
189
+ */
190
+ function getTrustDescription(level: number): string {
191
+ if (level <= 2) return 'low';
192
+ if (level <= 4) return 'developing';
193
+ if (level <= 6) return 'moderate';
194
+ if (level <= 8) return 'high';
195
+ return 'very high';
196
+ }
@@ -0,0 +1,20 @@
1
+ // Re-export all personality engine modules
2
+ export type { PersonalityModel } from './model.ts';
3
+ export {
4
+ loadPersonality,
5
+ savePersonality,
6
+ getPersonality,
7
+ updatePersonality,
8
+ } from './model.ts';
9
+
10
+ export type { InteractionSignal } from './learner.ts';
11
+ export {
12
+ extractSignals,
13
+ applySignals,
14
+ recordInteraction,
15
+ } from './learner.ts';
16
+
17
+ export {
18
+ getChannelPersonality,
19
+ personalityToPrompt,
20
+ } from './adapter.ts';
@@ -0,0 +1,209 @@
1
+ import type { PersonalityModel } from './model.ts';
2
+
3
+ export type InteractionSignal = {
4
+ type: 'user_feedback' | 'message_style' | 'explicit_preference';
5
+ data: Record<string, unknown>;
6
+ };
7
+
8
+ /**
9
+ * Clamp a number to a range
10
+ */
11
+ function clamp(value: number, min: number, max: number): number {
12
+ return Math.max(min, Math.min(max, value));
13
+ }
14
+
15
+ /**
16
+ * Analyze a user message for preference signals
17
+ */
18
+ export function extractSignals(userMessage: string, assistantResponse: string): InteractionSignal[] {
19
+ const signals: InteractionSignal[] = [];
20
+ const lowerMessage = userMessage.toLowerCase();
21
+
22
+ // Verbosity signals
23
+ if (
24
+ lowerMessage.includes('shorter') ||
25
+ lowerMessage.includes('brief') ||
26
+ lowerMessage.includes('tldr') ||
27
+ lowerMessage.includes('too long') ||
28
+ lowerMessage.includes('concise') ||
29
+ lowerMessage.includes('summarize')
30
+ ) {
31
+ signals.push({
32
+ type: 'user_feedback',
33
+ data: { preference: 'verbosity', direction: -1 },
34
+ });
35
+ }
36
+
37
+ if (
38
+ lowerMessage.includes('more detail') ||
39
+ lowerMessage.includes('explain') ||
40
+ lowerMessage.includes('elaborate') ||
41
+ lowerMessage.includes('tell me more') ||
42
+ lowerMessage.includes('expand on')
43
+ ) {
44
+ signals.push({
45
+ type: 'user_feedback',
46
+ data: { preference: 'verbosity', direction: 1 },
47
+ });
48
+ }
49
+
50
+ // Formality signals
51
+ if (
52
+ lowerMessage.includes('be more casual') ||
53
+ lowerMessage.includes('less formal') ||
54
+ lowerMessage.includes('relax') ||
55
+ lowerMessage.includes('informal')
56
+ ) {
57
+ signals.push({
58
+ type: 'explicit_preference',
59
+ data: { preference: 'formality', direction: -1 },
60
+ });
61
+ }
62
+
63
+ if (
64
+ lowerMessage.includes('be more formal') ||
65
+ lowerMessage.includes('professional') ||
66
+ lowerMessage.includes('polite')
67
+ ) {
68
+ signals.push({
69
+ type: 'explicit_preference',
70
+ data: { preference: 'formality', direction: 1 },
71
+ });
72
+ }
73
+
74
+ // Humor signals
75
+ if (
76
+ lowerMessage.includes('funny') ||
77
+ lowerMessage.includes('joke') ||
78
+ lowerMessage.includes('humorous') ||
79
+ lowerMessage.includes('make me laugh')
80
+ ) {
81
+ signals.push({
82
+ type: 'explicit_preference',
83
+ data: { preference: 'humor_level', direction: 1 },
84
+ });
85
+ }
86
+
87
+ if (
88
+ lowerMessage.includes('serious') ||
89
+ lowerMessage.includes('no jokes') ||
90
+ lowerMessage.includes('be serious')
91
+ ) {
92
+ signals.push({
93
+ type: 'explicit_preference',
94
+ data: { preference: 'humor_level', direction: -1 },
95
+ });
96
+ }
97
+
98
+ // Emoji usage detection (if user uses emojis, they probably like them)
99
+ const emojiRegex = /[\p{Emoji_Presentation}\p{Extended_Pictographic}]/gu;
100
+ if (emojiRegex.test(userMessage)) {
101
+ signals.push({
102
+ type: 'message_style',
103
+ data: { preference: 'emoji_usage', value: true },
104
+ });
105
+ }
106
+
107
+ // Format preference signals
108
+ if (
109
+ lowerMessage.includes('bullet points') ||
110
+ lowerMessage.includes('list format') ||
111
+ lowerMessage.includes('as a list')
112
+ ) {
113
+ signals.push({
114
+ type: 'explicit_preference',
115
+ data: { preference: 'preferred_format', value: 'lists' },
116
+ });
117
+ }
118
+
119
+ if (
120
+ lowerMessage.includes('table') ||
121
+ lowerMessage.includes('tabular format')
122
+ ) {
123
+ signals.push({
124
+ type: 'explicit_preference',
125
+ data: { preference: 'preferred_format', value: 'tables' },
126
+ });
127
+ }
128
+
129
+ if (
130
+ lowerMessage.includes('paragraph') ||
131
+ lowerMessage.includes('prose') ||
132
+ lowerMessage.includes('written out')
133
+ ) {
134
+ signals.push({
135
+ type: 'explicit_preference',
136
+ data: { preference: 'preferred_format', value: 'prose' },
137
+ });
138
+ }
139
+
140
+ return signals;
141
+ }
142
+
143
+ /**
144
+ * Apply signals to update personality
145
+ */
146
+ export function applySignals(personality: PersonalityModel, signals: InteractionSignal[]): PersonalityModel {
147
+ const updated = { ...personality };
148
+
149
+ for (const signal of signals) {
150
+ const { preference, direction, value } = signal.data as {
151
+ preference?: string;
152
+ direction?: number;
153
+ value?: any;
154
+ };
155
+
156
+ if (!preference) continue;
157
+
158
+ // Handle numeric preferences (verbosity, formality, humor_level)
159
+ if (
160
+ preference === 'verbosity' ||
161
+ preference === 'formality' ||
162
+ preference === 'humor_level'
163
+ ) {
164
+ const currentValue = updated.learned_preferences[preference as keyof typeof updated.learned_preferences] as number;
165
+ const adjustment = direction ?? 0;
166
+ const newValue = clamp(currentValue + adjustment, 0, 10);
167
+ (updated.learned_preferences as any)[preference] = newValue;
168
+ }
169
+
170
+ // Handle boolean preferences
171
+ if (preference === 'emoji_usage' && typeof value === 'boolean') {
172
+ updated.learned_preferences.emoji_usage = value;
173
+ }
174
+
175
+ // Handle enum preferences
176
+ if (preference === 'preferred_format' && typeof value === 'string') {
177
+ const validFormats: Array<PersonalityModel['learned_preferences']['preferred_format']> = [
178
+ 'lists',
179
+ 'prose',
180
+ 'tables',
181
+ 'adaptive',
182
+ ];
183
+ if (validFormats.includes(value as any)) {
184
+ updated.learned_preferences.preferred_format = value as any;
185
+ }
186
+ }
187
+ }
188
+
189
+ return updated;
190
+ }
191
+
192
+ /**
193
+ * Increment message count and adjust trust
194
+ */
195
+ export function recordInteraction(personality: PersonalityModel): PersonalityModel {
196
+ const updated = { ...personality };
197
+ updated.relationship.message_count += 1;
198
+
199
+ // Trust grows slowly over time, caps at 10
200
+ // Every 10 messages = +1 trust (up to max of 10)
201
+ const trustFromInteractions = Math.min(
202
+ 10,
203
+ 3 + Math.floor(updated.relationship.message_count / 10)
204
+ );
205
+
206
+ updated.relationship.trust_level = clamp(trustFromInteractions, 0, 10);
207
+
208
+ return updated;
209
+ }