@usejarvis/brain 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (266) hide show
  1. package/LICENSE +153 -0
  2. package/README.md +278 -0
  3. package/bin/jarvis.ts +413 -0
  4. package/package.json +74 -0
  5. package/scripts/ensure-bun.cjs +8 -0
  6. package/src/actions/README.md +421 -0
  7. package/src/actions/app-control/desktop-controller.test.ts +26 -0
  8. package/src/actions/app-control/desktop-controller.ts +438 -0
  9. package/src/actions/app-control/interface.ts +64 -0
  10. package/src/actions/app-control/linux.ts +273 -0
  11. package/src/actions/app-control/macos.ts +54 -0
  12. package/src/actions/app-control/sidecar-launcher.test.ts +23 -0
  13. package/src/actions/app-control/sidecar-launcher.ts +286 -0
  14. package/src/actions/app-control/windows.ts +44 -0
  15. package/src/actions/browser/cdp.ts +138 -0
  16. package/src/actions/browser/chrome-launcher.ts +252 -0
  17. package/src/actions/browser/session.ts +437 -0
  18. package/src/actions/browser/stealth.ts +49 -0
  19. package/src/actions/index.ts +20 -0
  20. package/src/actions/terminal/executor.ts +157 -0
  21. package/src/actions/terminal/wsl-bridge.ts +126 -0
  22. package/src/actions/test.ts +93 -0
  23. package/src/actions/tools/agents.ts +321 -0
  24. package/src/actions/tools/builtin.ts +846 -0
  25. package/src/actions/tools/commitments.ts +192 -0
  26. package/src/actions/tools/content.ts +217 -0
  27. package/src/actions/tools/delegate.ts +147 -0
  28. package/src/actions/tools/desktop.test.ts +55 -0
  29. package/src/actions/tools/desktop.ts +305 -0
  30. package/src/actions/tools/goals.ts +376 -0
  31. package/src/actions/tools/local-tools-guard.ts +20 -0
  32. package/src/actions/tools/registry.ts +171 -0
  33. package/src/actions/tools/research.ts +111 -0
  34. package/src/actions/tools/sidecar-list.ts +57 -0
  35. package/src/actions/tools/sidecar-route.ts +105 -0
  36. package/src/actions/tools/workflows.ts +216 -0
  37. package/src/agents/agent.ts +132 -0
  38. package/src/agents/delegation.ts +107 -0
  39. package/src/agents/hierarchy.ts +113 -0
  40. package/src/agents/index.ts +19 -0
  41. package/src/agents/messaging.ts +125 -0
  42. package/src/agents/orchestrator.ts +576 -0
  43. package/src/agents/role-discovery.ts +61 -0
  44. package/src/agents/sub-agent-runner.ts +307 -0
  45. package/src/agents/task-manager.ts +151 -0
  46. package/src/authority/approval-delivery.ts +59 -0
  47. package/src/authority/approval.ts +196 -0
  48. package/src/authority/audit.ts +158 -0
  49. package/src/authority/authority.test.ts +519 -0
  50. package/src/authority/deferred-executor.ts +103 -0
  51. package/src/authority/emergency.ts +66 -0
  52. package/src/authority/engine.ts +297 -0
  53. package/src/authority/index.ts +12 -0
  54. package/src/authority/learning.ts +111 -0
  55. package/src/authority/tool-action-map.ts +74 -0
  56. package/src/awareness/analytics.ts +466 -0
  57. package/src/awareness/awareness.test.ts +332 -0
  58. package/src/awareness/capture-engine.ts +305 -0
  59. package/src/awareness/context-graph.ts +130 -0
  60. package/src/awareness/context-tracker.ts +349 -0
  61. package/src/awareness/index.ts +25 -0
  62. package/src/awareness/intelligence.ts +321 -0
  63. package/src/awareness/ocr-engine.ts +88 -0
  64. package/src/awareness/service.ts +528 -0
  65. package/src/awareness/struggle-detector.ts +342 -0
  66. package/src/awareness/suggestion-engine.ts +476 -0
  67. package/src/awareness/types.ts +201 -0
  68. package/src/cli/autostart.ts +241 -0
  69. package/src/cli/deps.ts +449 -0
  70. package/src/cli/doctor.ts +230 -0
  71. package/src/cli/helpers.ts +401 -0
  72. package/src/cli/onboard.ts +580 -0
  73. package/src/comms/README.md +329 -0
  74. package/src/comms/auth-error.html +48 -0
  75. package/src/comms/channels/discord.ts +228 -0
  76. package/src/comms/channels/signal.ts +56 -0
  77. package/src/comms/channels/telegram.ts +316 -0
  78. package/src/comms/channels/whatsapp.ts +60 -0
  79. package/src/comms/channels.test.ts +173 -0
  80. package/src/comms/desktop-notify.ts +114 -0
  81. package/src/comms/example.ts +129 -0
  82. package/src/comms/index.ts +129 -0
  83. package/src/comms/streaming.ts +142 -0
  84. package/src/comms/voice.test.ts +152 -0
  85. package/src/comms/voice.ts +291 -0
  86. package/src/comms/websocket.test.ts +409 -0
  87. package/src/comms/websocket.ts +473 -0
  88. package/src/config/README.md +387 -0
  89. package/src/config/index.ts +6 -0
  90. package/src/config/loader.test.ts +137 -0
  91. package/src/config/loader.ts +142 -0
  92. package/src/config/types.ts +260 -0
  93. package/src/daemon/README.md +232 -0
  94. package/src/daemon/agent-service-interface.ts +9 -0
  95. package/src/daemon/agent-service.ts +600 -0
  96. package/src/daemon/api-routes.ts +2119 -0
  97. package/src/daemon/background-agent-service.ts +396 -0
  98. package/src/daemon/background-agent.test.ts +78 -0
  99. package/src/daemon/channel-service.ts +201 -0
  100. package/src/daemon/commitment-executor.ts +297 -0
  101. package/src/daemon/event-classifier.ts +239 -0
  102. package/src/daemon/event-coalescer.ts +123 -0
  103. package/src/daemon/event-reactor.ts +214 -0
  104. package/src/daemon/health.ts +220 -0
  105. package/src/daemon/index.ts +1004 -0
  106. package/src/daemon/llm-settings.ts +316 -0
  107. package/src/daemon/observer-service.ts +150 -0
  108. package/src/daemon/pid.ts +98 -0
  109. package/src/daemon/research-queue.ts +155 -0
  110. package/src/daemon/services.ts +175 -0
  111. package/src/daemon/ws-service.ts +788 -0
  112. package/src/goals/accountability.ts +240 -0
  113. package/src/goals/awareness-bridge.ts +185 -0
  114. package/src/goals/estimator.ts +185 -0
  115. package/src/goals/events.ts +28 -0
  116. package/src/goals/goals.test.ts +400 -0
  117. package/src/goals/integration.test.ts +329 -0
  118. package/src/goals/nl-builder.test.ts +220 -0
  119. package/src/goals/nl-builder.ts +256 -0
  120. package/src/goals/rhythm.test.ts +177 -0
  121. package/src/goals/rhythm.ts +275 -0
  122. package/src/goals/service.test.ts +135 -0
  123. package/src/goals/service.ts +348 -0
  124. package/src/goals/types.ts +106 -0
  125. package/src/goals/workflow-bridge.ts +96 -0
  126. package/src/integrations/google-api.ts +134 -0
  127. package/src/integrations/google-auth.ts +175 -0
  128. package/src/llm/README.md +291 -0
  129. package/src/llm/anthropic.ts +386 -0
  130. package/src/llm/gemini.ts +371 -0
  131. package/src/llm/index.ts +19 -0
  132. package/src/llm/manager.ts +153 -0
  133. package/src/llm/ollama.ts +307 -0
  134. package/src/llm/openai.ts +350 -0
  135. package/src/llm/provider.test.ts +231 -0
  136. package/src/llm/provider.ts +60 -0
  137. package/src/llm/test.ts +87 -0
  138. package/src/observers/README.md +278 -0
  139. package/src/observers/calendar.ts +113 -0
  140. package/src/observers/clipboard.ts +136 -0
  141. package/src/observers/email.ts +109 -0
  142. package/src/observers/example.ts +58 -0
  143. package/src/observers/file-watcher.ts +124 -0
  144. package/src/observers/index.ts +159 -0
  145. package/src/observers/notifications.ts +197 -0
  146. package/src/observers/observers.test.ts +203 -0
  147. package/src/observers/processes.ts +225 -0
  148. package/src/personality/README.md +61 -0
  149. package/src/personality/adapter.ts +196 -0
  150. package/src/personality/index.ts +20 -0
  151. package/src/personality/learner.ts +209 -0
  152. package/src/personality/model.ts +132 -0
  153. package/src/personality/personality.test.ts +236 -0
  154. package/src/roles/README.md +252 -0
  155. package/src/roles/authority.ts +119 -0
  156. package/src/roles/example-usage.ts +198 -0
  157. package/src/roles/index.ts +42 -0
  158. package/src/roles/loader.ts +143 -0
  159. package/src/roles/prompt-builder.ts +194 -0
  160. package/src/roles/test-multi.ts +102 -0
  161. package/src/roles/test-role.yaml +77 -0
  162. package/src/roles/test-utils.ts +93 -0
  163. package/src/roles/test.ts +106 -0
  164. package/src/roles/tool-guide.ts +190 -0
  165. package/src/roles/types.ts +36 -0
  166. package/src/roles/utils.ts +200 -0
  167. package/src/scripts/google-setup.ts +168 -0
  168. package/src/sidecar/connection.ts +179 -0
  169. package/src/sidecar/index.ts +6 -0
  170. package/src/sidecar/manager.ts +542 -0
  171. package/src/sidecar/protocol.ts +85 -0
  172. package/src/sidecar/rpc.ts +161 -0
  173. package/src/sidecar/scheduler.ts +136 -0
  174. package/src/sidecar/types.ts +112 -0
  175. package/src/sidecar/validator.ts +144 -0
  176. package/src/vault/README.md +110 -0
  177. package/src/vault/awareness.ts +341 -0
  178. package/src/vault/commitments.ts +299 -0
  179. package/src/vault/content-pipeline.ts +260 -0
  180. package/src/vault/conversations.ts +173 -0
  181. package/src/vault/entities.ts +180 -0
  182. package/src/vault/extractor.test.ts +356 -0
  183. package/src/vault/extractor.ts +345 -0
  184. package/src/vault/facts.ts +190 -0
  185. package/src/vault/goals.ts +477 -0
  186. package/src/vault/index.ts +87 -0
  187. package/src/vault/keychain.ts +99 -0
  188. package/src/vault/observations.ts +115 -0
  189. package/src/vault/relationships.ts +178 -0
  190. package/src/vault/retrieval.test.ts +126 -0
  191. package/src/vault/retrieval.ts +227 -0
  192. package/src/vault/schema.ts +658 -0
  193. package/src/vault/settings.ts +38 -0
  194. package/src/vault/vectors.ts +92 -0
  195. package/src/vault/workflows.ts +403 -0
  196. package/src/workflows/auto-suggest.ts +290 -0
  197. package/src/workflows/engine.ts +366 -0
  198. package/src/workflows/events.ts +24 -0
  199. package/src/workflows/executor.ts +207 -0
  200. package/src/workflows/nl-builder.ts +198 -0
  201. package/src/workflows/nodes/actions/agent-task.ts +73 -0
  202. package/src/workflows/nodes/actions/calendar-action.ts +85 -0
  203. package/src/workflows/nodes/actions/code-execution.ts +73 -0
  204. package/src/workflows/nodes/actions/discord.ts +77 -0
  205. package/src/workflows/nodes/actions/file-write.ts +73 -0
  206. package/src/workflows/nodes/actions/gmail.ts +69 -0
  207. package/src/workflows/nodes/actions/http-request.ts +117 -0
  208. package/src/workflows/nodes/actions/notification.ts +85 -0
  209. package/src/workflows/nodes/actions/run-tool.ts +55 -0
  210. package/src/workflows/nodes/actions/send-message.ts +82 -0
  211. package/src/workflows/nodes/actions/shell-command.ts +76 -0
  212. package/src/workflows/nodes/actions/telegram.ts +60 -0
  213. package/src/workflows/nodes/builtin.ts +119 -0
  214. package/src/workflows/nodes/error/error-handler.ts +37 -0
  215. package/src/workflows/nodes/error/fallback.ts +47 -0
  216. package/src/workflows/nodes/error/retry.ts +82 -0
  217. package/src/workflows/nodes/logic/delay.ts +42 -0
  218. package/src/workflows/nodes/logic/if-else.ts +41 -0
  219. package/src/workflows/nodes/logic/loop.ts +90 -0
  220. package/src/workflows/nodes/logic/merge.ts +38 -0
  221. package/src/workflows/nodes/logic/race.ts +40 -0
  222. package/src/workflows/nodes/logic/switch.ts +59 -0
  223. package/src/workflows/nodes/logic/template-render.ts +53 -0
  224. package/src/workflows/nodes/logic/variable-get.ts +37 -0
  225. package/src/workflows/nodes/logic/variable-set.ts +59 -0
  226. package/src/workflows/nodes/registry.ts +99 -0
  227. package/src/workflows/nodes/transform/aggregate.ts +99 -0
  228. package/src/workflows/nodes/transform/csv-parse.ts +70 -0
  229. package/src/workflows/nodes/transform/json-parse.ts +63 -0
  230. package/src/workflows/nodes/transform/map-filter.ts +84 -0
  231. package/src/workflows/nodes/transform/regex-match.ts +89 -0
  232. package/src/workflows/nodes/triggers/calendar.ts +33 -0
  233. package/src/workflows/nodes/triggers/clipboard.ts +32 -0
  234. package/src/workflows/nodes/triggers/cron.ts +40 -0
  235. package/src/workflows/nodes/triggers/email.ts +40 -0
  236. package/src/workflows/nodes/triggers/file-change.ts +45 -0
  237. package/src/workflows/nodes/triggers/git.ts +46 -0
  238. package/src/workflows/nodes/triggers/manual.ts +23 -0
  239. package/src/workflows/nodes/triggers/poll.ts +81 -0
  240. package/src/workflows/nodes/triggers/process.ts +44 -0
  241. package/src/workflows/nodes/triggers/screen-event.ts +37 -0
  242. package/src/workflows/nodes/triggers/webhook.ts +39 -0
  243. package/src/workflows/safe-eval.ts +139 -0
  244. package/src/workflows/template.ts +118 -0
  245. package/src/workflows/triggers/cron.ts +311 -0
  246. package/src/workflows/triggers/manager.ts +285 -0
  247. package/src/workflows/triggers/observer-bridge.ts +172 -0
  248. package/src/workflows/triggers/poller.ts +201 -0
  249. package/src/workflows/triggers/screen-condition.ts +218 -0
  250. package/src/workflows/triggers/triggers.test.ts +740 -0
  251. package/src/workflows/triggers/webhook.ts +191 -0
  252. package/src/workflows/types.ts +133 -0
  253. package/src/workflows/variables.ts +72 -0
  254. package/src/workflows/workflows.test.ts +383 -0
  255. package/src/workflows/yaml.ts +104 -0
  256. package/ui/dist/index-j75njzc1.css +1199 -0
  257. package/ui/dist/index-p2zh407q.js +80603 -0
  258. package/ui/dist/index.html +13 -0
  259. package/ui/public/openwakeword/models/embedding_model.onnx +0 -0
  260. package/ui/public/openwakeword/models/hey_jarvis_v0.1.onnx +0 -0
  261. package/ui/public/openwakeword/models/melspectrogram.onnx +0 -0
  262. package/ui/public/openwakeword/models/silero_vad.onnx +0 -0
  263. package/ui/public/ort/ort-wasm-simd-threaded.jsep.mjs +106 -0
  264. package/ui/public/ort/ort-wasm-simd-threaded.jsep.wasm +0 -0
  265. package/ui/public/ort/ort-wasm-simd-threaded.mjs +59 -0
  266. package/ui/public/ort/ort-wasm-simd-threaded.wasm +0 -0
package/bin/jarvis.ts ADDED
@@ -0,0 +1,413 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * J.A.R.V.I.S. CLI Entry Point
4
+ *
5
+ * Usage:
6
+ * jarvis start [--port N] [-d|--detach] Start the daemon
7
+ * jarvis stop Stop the running daemon
8
+ * jarvis status Show daemon status
9
+ * jarvis onboard Interactive setup wizard
10
+ * jarvis doctor Check environment & connectivity
11
+ * jarvis version Print version
12
+ * jarvis help Show this help
13
+ */
14
+
15
+ import { join } from 'node:path';
16
+ import { readFileSync, existsSync, openSync } from 'node:fs';
17
+ import { spawn } from 'node:child_process';
18
+ import { writePid, clearPid, isRunning, getLogPath } from '../src/daemon/pid.ts';
19
+ import { c } from '../src/cli/helpers.ts';
20
+
21
+ const PACKAGE_ROOT = join(import.meta.dir, '..');
22
+
23
+ function getVersion(): string {
24
+ try {
25
+ const pkg = JSON.parse(readFileSync(join(PACKAGE_ROOT, 'package.json'), 'utf-8'));
26
+ return pkg.version || '0.0.0';
27
+ } catch {
28
+ return '0.0.0';
29
+ }
30
+ }
31
+
32
+ function printHelp(): void {
33
+ console.log(`
34
+ ${c.cyan('J.A.R.V.I.S.')} ${c.dim(`v${getVersion()}`)}
35
+ Just A Rather Very Intelligent System
36
+
37
+ ${c.bold('Usage:')}
38
+ jarvis <command> [options]
39
+
40
+ ${c.bold('Commands:')}
41
+ ${c.cyan('start')} Start the JARVIS daemon
42
+ ${c.cyan('stop')} Stop the running daemon
43
+ ${c.cyan('restart')} Restart the daemon (stop + start)
44
+ ${c.cyan('status')} Show daemon status
45
+ ${c.cyan('logs')} Tail the daemon log file
46
+ ${c.cyan('update')} Update JARVIS to the latest version
47
+ ${c.cyan('onboard')} Interactive first-time setup wizard
48
+ ${c.cyan('doctor')} Check environment and connectivity
49
+ ${c.cyan('version')} Print version number
50
+ ${c.cyan('help')} Show this help message
51
+
52
+ ${c.bold('Start options:')}
53
+ --port <N> Override daemon port (default: 3142)
54
+ -d, --detach Run as background daemon
55
+ --no-open Don't auto-open dashboard in browser
56
+
57
+ ${c.bold('Logs options:')}
58
+ -f, --follow Follow log output (like tail -f)
59
+ -n, --lines <N> Number of lines to show (default: 50)
60
+
61
+ ${c.bold('Examples:')}
62
+ jarvis start Start in foreground
63
+ jarvis start -d Start as background daemon
64
+ jarvis start --port 8080 Start on custom port
65
+ jarvis restart Restart with same settings
66
+ jarvis logs -f Follow live log output
67
+ jarvis update Update to latest version
68
+ jarvis onboard Run the setup wizard
69
+ jarvis doctor Check if everything is working
70
+ `);
71
+ }
72
+
73
+ async function cmdStart(args: string[]): Promise<void> {
74
+ const detach = args.includes('--detach') || args.includes('-d');
75
+ const noOpen = args.includes('--no-open');
76
+
77
+ // Parse --port
78
+ let port: number | undefined;
79
+ const portIdx = args.indexOf('--port');
80
+ if (portIdx !== -1 && args[portIdx + 1]) {
81
+ port = parseInt(args[portIdx + 1]!, 10);
82
+ if (isNaN(port) || port < 1 || port > 65535) {
83
+ console.error(c.red('Error: --port requires a number between 1 and 65535'));
84
+ process.exit(1);
85
+ }
86
+ }
87
+
88
+ // Check if already running
89
+ const existingPid = isRunning();
90
+ if (existingPid) {
91
+ console.log(c.yellow(`JARVIS is already running (PID ${existingPid})`));
92
+ console.log(c.dim(` Stop it first with: jarvis stop`));
93
+ process.exit(1);
94
+ }
95
+
96
+ if (!detach) {
97
+ // Run in foreground — just import and call startDaemon
98
+ writePid(process.pid);
99
+ process.on('exit', () => clearPid());
100
+ process.on('SIGINT', () => { clearPid(); process.exit(0); });
101
+ process.on('SIGTERM', () => { clearPid(); process.exit(0); });
102
+
103
+ const { startDaemon } = await import('../src/daemon/index.ts');
104
+ await startDaemon({ port, ...(port ? {} : {}) });
105
+
106
+ if (!noOpen) {
107
+ openDashboard(port ?? 3142);
108
+ }
109
+ } else {
110
+ // Run in background — spawn a detached child process with log file
111
+ console.log(c.cyan('Starting J.A.R.V.I.S. daemon...'));
112
+
113
+ const logPath = getLogPath();
114
+ const logFile = Bun.file(logPath);
115
+
116
+ const daemonArgs = [join(PACKAGE_ROOT, 'bin/jarvis.ts'), 'start', '--no-open'];
117
+ if (port) daemonArgs.push('--port', String(port));
118
+
119
+ const logFd = openSync(logPath, 'a');
120
+ const child = spawn('bun', daemonArgs, {
121
+ detached: true,
122
+ stdio: ['ignore', logFd, logFd],
123
+ env: { ...process.env },
124
+ });
125
+ child.unref();
126
+
127
+ // Poll for the daemon to write its PID (up to 10s)
128
+ let runningPid: number | null = null;
129
+ for (let i = 0; i < 20; i++) {
130
+ await new Promise(resolve => setTimeout(resolve, 500));
131
+ runningPid = isRunning();
132
+ if (runningPid) break;
133
+ }
134
+
135
+ if (runningPid) {
136
+ console.log(c.green(`✓ JARVIS daemon started (PID ${runningPid})`));
137
+ console.log(c.dim(` Dashboard: http://localhost:${port ?? 3142}`));
138
+ console.log(c.dim(` Logs: ${logPath}`));
139
+ console.log(c.dim(` Stop with: jarvis stop`));
140
+
141
+ if (!noOpen) {
142
+ openDashboard(port ?? 3142);
143
+ }
144
+ } else {
145
+ console.log(c.red('✗ Failed to start daemon. Check logs:'));
146
+ console.log(c.dim(` ${logPath}`));
147
+ process.exit(1);
148
+ }
149
+ }
150
+ }
151
+
152
+ async function cmdStop(): Promise<void> {
153
+ const pid = isRunning();
154
+ if (!pid) {
155
+ console.log(c.yellow('JARVIS is not running.'));
156
+ return;
157
+ }
158
+
159
+ console.log(c.cyan(`Stopping JARVIS daemon (PID ${pid})...`));
160
+ try {
161
+ process.kill(pid, 'SIGTERM');
162
+
163
+ // Wait up to 5s for graceful shutdown, then SIGKILL
164
+ let alive = true;
165
+ for (let i = 0; i < 10; i++) {
166
+ await new Promise(resolve => setTimeout(resolve, 500));
167
+ try { process.kill(pid, 0); } catch { alive = false; break; }
168
+ }
169
+
170
+ if (alive) {
171
+ console.log(c.dim(' Process still alive, sending SIGKILL...'));
172
+ try { process.kill(pid, 'SIGKILL'); } catch { /* already gone */ }
173
+ }
174
+
175
+ clearPid();
176
+ console.log(c.green('✓ JARVIS daemon stopped.'));
177
+ } catch (err) {
178
+ console.error(c.red(`Failed to stop process ${pid}: ${err}`));
179
+ clearPid();
180
+ }
181
+ }
182
+
183
+ function cmdStatus(): void {
184
+ const pid = isRunning();
185
+ if (pid) {
186
+ console.log(`${c.green('●')} JARVIS is ${c.green('running')} (PID ${pid})`);
187
+
188
+ // Try to read the port from config
189
+ try {
190
+ const { homedir } = require('node:os');
191
+ const configPath = join(homedir(), '.jarvis', 'config.yaml');
192
+ const YAML = require('yaml');
193
+ const text = readFileSync(configPath, 'utf-8');
194
+ const cfg = YAML.parse(text);
195
+ const port = cfg?.daemon?.port ?? 3142;
196
+ console.log(c.dim(` Dashboard: http://localhost:${port}`));
197
+ } catch {
198
+ console.log(c.dim(` Dashboard: http://localhost:3142`));
199
+ }
200
+
201
+ console.log(c.dim(` Stop with: jarvis stop`));
202
+ } else {
203
+ console.log(`${c.red('●')} JARVIS is ${c.red('stopped')}`);
204
+ console.log(c.dim(` Start with: jarvis start`));
205
+ }
206
+ }
207
+
208
+ async function cmdOnboard(): Promise<void> {
209
+ const { runOnboard } = await import('../src/cli/onboard.ts');
210
+ await runOnboard();
211
+ }
212
+
213
+ async function cmdDoctor(): Promise<void> {
214
+ const { runDoctor } = await import('../src/cli/doctor.ts');
215
+ await runDoctor();
216
+ }
217
+
218
+ async function cmdRestart(args: string[]): Promise<void> {
219
+ const pid = isRunning();
220
+ if (pid) {
221
+ await cmdStop();
222
+ }
223
+
224
+ console.log('');
225
+ await cmdStart(args);
226
+ }
227
+
228
+ function cmdLogs(args: string[]): void {
229
+ const logPath = getLogPath();
230
+
231
+ if (!existsSync(logPath)) {
232
+ console.log(c.yellow('No log file found. Start the daemon first: jarvis start'));
233
+ return;
234
+ }
235
+
236
+ const follow = args.includes('-f') || args.includes('--follow');
237
+
238
+ // Parse --lines / -n
239
+ let lines = 50;
240
+ const nIdx = args.indexOf('-n') !== -1 ? args.indexOf('-n') : args.indexOf('--lines');
241
+ if (nIdx !== -1 && args[nIdx + 1]) {
242
+ const n = parseInt(args[nIdx + 1], 10);
243
+ if (!isNaN(n) && n > 0) lines = n;
244
+ }
245
+
246
+ console.log(c.dim(`Log file: ${logPath}\n`));
247
+
248
+ if (follow) {
249
+ // tail -f equivalent
250
+ const tailProc = Bun.spawn(['tail', '-f', '-n', String(lines), logPath], {
251
+ stdio: ['ignore', 'inherit', 'inherit'],
252
+ });
253
+
254
+ process.on('SIGINT', () => {
255
+ tailProc.kill();
256
+ process.exit(0);
257
+ });
258
+ } else {
259
+ // Just show last N lines
260
+ const tailProc = Bun.spawnSync(['tail', '-n', String(lines), logPath]);
261
+ process.stdout.write(tailProc.stdout);
262
+ }
263
+ }
264
+
265
+ async function cmdUpdate(): Promise<void> {
266
+ console.log(c.cyan('Checking for updates...\n'));
267
+
268
+ // Get current version
269
+ const currentVersion = getVersion();
270
+ console.log(` Current version: ${c.bold(currentVersion)}`);
271
+
272
+ // Check if daemon is running (we'll restart it after update)
273
+ const wasRunning = isRunning();
274
+
275
+ // Stop daemon if running
276
+ if (wasRunning) {
277
+ console.log(c.dim(' Stopping daemon before update...'));
278
+ try {
279
+ process.kill(wasRunning, 'SIGTERM');
280
+ clearPid();
281
+ await new Promise(resolve => setTimeout(resolve, 1000));
282
+ } catch {
283
+ clearPid();
284
+ }
285
+ }
286
+
287
+ // Update via git pull + bun install (not npm — package is not published)
288
+ console.log('');
289
+ const gitPull = Bun.spawnSync(['git', 'pull', '--ff-only'], {
290
+ cwd: PACKAGE_ROOT,
291
+ stdio: ['ignore', 'pipe', 'pipe'],
292
+ env: { ...process.env },
293
+ });
294
+
295
+ if (gitPull.exitCode !== 0) {
296
+ const stderr = gitPull.stderr.toString();
297
+ // If not a git repo, try the install dir
298
+ const installDir = join(require('node:os').homedir(), '.jarvis', 'daemon');
299
+ const gitPull2 = Bun.spawnSync(['git', 'pull', '--ff-only'], {
300
+ cwd: installDir,
301
+ stdio: ['ignore', 'pipe', 'pipe'],
302
+ env: { ...process.env },
303
+ });
304
+
305
+ if (gitPull2.exitCode !== 0) {
306
+ console.log(c.red('✗ Update failed (git pull):'));
307
+ console.log(c.dim(` ${gitPull2.stderr.toString().trim() || stderr.trim()}`));
308
+ if (wasRunning) {
309
+ console.log(c.dim('\n Restarting daemon...'));
310
+ await cmdStart(['--no-open']);
311
+ }
312
+ process.exit(1);
313
+ }
314
+ }
315
+
316
+ // Reinstall dependencies
317
+ const bunInstall = Bun.spawnSync(['bun', 'install'], {
318
+ cwd: PACKAGE_ROOT,
319
+ stdio: ['ignore', 'pipe', 'pipe'],
320
+ env: { ...process.env },
321
+ });
322
+
323
+ if (bunInstall.exitCode !== 0) {
324
+ console.log(c.yellow('! Dependencies may need manual refresh: bun install'));
325
+ }
326
+
327
+ // Get new version
328
+ const newVersion = getVersion();
329
+ if (newVersion === currentVersion) {
330
+ console.log(c.green(`✓ Already on the latest version (${currentVersion})`));
331
+ } else {
332
+ console.log(c.green(`✓ Updated: ${currentVersion} → ${newVersion}`));
333
+ }
334
+
335
+ // Restart daemon if it was running
336
+ if (wasRunning) {
337
+ console.log(c.dim('\nRestarting daemon...'));
338
+ await cmdStart(['--no-open']);
339
+ }
340
+ }
341
+
342
+ function openDashboard(port: number): void {
343
+ const url = `http://localhost:${port}`;
344
+ try {
345
+ const platform = process.platform;
346
+ if (platform === 'darwin') {
347
+ Bun.spawn(['open', url], { stdio: ['ignore', 'ignore', 'ignore'] });
348
+ } else {
349
+ // Check WSL first
350
+ const { readFileSync } = require('node:fs');
351
+ try {
352
+ const version = readFileSync('/proc/version', 'utf-8');
353
+ if (version.toLowerCase().includes('microsoft')) {
354
+ Bun.spawn(['wslview', url], { stdio: ['ignore', 'ignore', 'ignore'] });
355
+ return;
356
+ }
357
+ } catch {}
358
+ // Regular Linux
359
+ Bun.spawn(['xdg-open', url], { stdio: ['ignore', 'ignore', 'ignore'] });
360
+ }
361
+ } catch {
362
+ // Silently fail — user can open manually
363
+ }
364
+ }
365
+
366
+ // ── Main ─────────────────────────────────────────────────────────────
367
+
368
+ const args = process.argv.slice(2);
369
+ const command = args[0] || 'help';
370
+ const commandArgs = args.slice(1);
371
+
372
+ switch (command) {
373
+ case 'start':
374
+ await cmdStart(commandArgs);
375
+ break;
376
+ case 'stop':
377
+ await cmdStop();
378
+ break;
379
+ case 'restart':
380
+ await cmdRestart(commandArgs);
381
+ break;
382
+ case 'status':
383
+ cmdStatus();
384
+ break;
385
+ case 'logs':
386
+ case 'log':
387
+ cmdLogs(commandArgs);
388
+ break;
389
+ case 'update':
390
+ case 'upgrade':
391
+ await cmdUpdate();
392
+ break;
393
+ case 'onboard':
394
+ await cmdOnboard();
395
+ break;
396
+ case 'doctor':
397
+ await cmdDoctor();
398
+ break;
399
+ case 'version':
400
+ case '-v':
401
+ case '--version':
402
+ console.log(getVersion());
403
+ break;
404
+ case 'help':
405
+ case '-h':
406
+ case '--help':
407
+ printHelp();
408
+ break;
409
+ default:
410
+ console.error(c.red(`Unknown command: ${command}`));
411
+ console.log(c.dim('Run "jarvis help" for usage information.'));
412
+ process.exit(1);
413
+ }
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "@usejarvis/brain",
3
+ "version": "0.1.0",
4
+ "description": "J.A.R.V.I.S. — Just A Rather Very Intelligent System. An always-on autonomous AI daemon.",
5
+ "module": "src/daemon/index.ts",
6
+ "type": "module",
7
+ "bin": {
8
+ "jarvis": "bin/jarvis.ts"
9
+ },
10
+ "engines": {
11
+ "bun": ">=1.0.0"
12
+ },
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/vierisid/jarvis.git"
16
+ },
17
+ "license": "Apache-2.0",
18
+ "keywords": [
19
+ "jarvis",
20
+ "ai",
21
+ "daemon",
22
+ "assistant",
23
+ "cli"
24
+ ],
25
+ "files": [
26
+ "bin/",
27
+ "src/",
28
+ "ui/dist/",
29
+ "ui/public/",
30
+ "scripts/ensure-bun.cjs",
31
+ "README.md"
32
+ ],
33
+ "scripts": {
34
+ "start": "bun run src/daemon/index.ts",
35
+ "dev": "bun --hot run src/daemon/index.ts",
36
+ "copy:models": "mkdir -p ui/public/openwakeword/models ui/public/ort && cp node_modules/openwakeword-wasm-browser/models/melspectrogram.onnx node_modules/openwakeword-wasm-browser/models/embedding_model.onnx node_modules/openwakeword-wasm-browser/models/silero_vad.onnx node_modules/openwakeword-wasm-browser/models/hey_jarvis_v0.1.onnx ui/public/openwakeword/models/ && cp node_modules/onnxruntime-web/dist/ort-wasm-simd-threaded.jsep.wasm node_modules/onnxruntime-web/dist/ort-wasm-simd-threaded.wasm node_modules/onnxruntime-web/dist/ort-wasm-simd-threaded.jsep.mjs node_modules/onnxruntime-web/dist/ort-wasm-simd-threaded.mjs ui/public/ort/",
37
+ "prebuild:ui": "bun run copy:models",
38
+ "build:ui": "bun build ui/index.html --outdir ui/dist",
39
+ "test": "bun test",
40
+ "db:init": "bun run src/vault/schema.ts",
41
+ "setup": "bun run scripts/setup-config.ts",
42
+ "test:llm": "bun run src/llm/test.ts",
43
+ "examples": "bun run examples/llm-integration.ts",
44
+ "setup:google": "bun run src/scripts/google-setup.ts",
45
+ "postinstall": "node scripts/ensure-bun.cjs && bun run copy:models 2>/dev/null || true",
46
+ "prepare": "git config core.hooksPath .githooks 2>/dev/null || true",
47
+ "prepublishOnly": "bun run copy:models && bun run build:ui"
48
+ },
49
+ "dependencies": {
50
+ "@types/react": "^19.2.14",
51
+ "@types/react-dom": "^19.2.3",
52
+ "@xyflow/react": "^12.10.1",
53
+ "discord.js": "^14.25.1",
54
+ "edge-tts-universal": "^1.4.0",
55
+ "highlight.js": "^11.11.1",
56
+ "jose": "^6.2.0",
57
+ "openwakeword-wasm-browser": "^0.1.1",
58
+ "react": "^19.2.4",
59
+ "react-dom": "^19.2.4",
60
+ "react-markdown": "^10.1.0",
61
+ "rehype-highlight": "^7.0.2",
62
+ "remark-gfm": "^4.0.1",
63
+ "sharp": "^0.34.5",
64
+ "tailwindcss": "^4.2.1",
65
+ "tesseract.js": "^7.0.0",
66
+ "yaml": "^2.7.0"
67
+ },
68
+ "devDependencies": {
69
+ "@types/bun": "latest"
70
+ },
71
+ "peerDependencies": {
72
+ "typescript": "^5"
73
+ }
74
+ }
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ const { execSync } = require('child_process');
3
+ try {
4
+ execSync('bun --version', { stdio: 'ignore' });
5
+ } catch {
6
+ console.log('Bun runtime not found. Installing...');
7
+ execSync('curl -fsSL https://bun.sh/install | bash', { stdio: 'inherit' });
8
+ }