@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,195 @@
1
+ /**
2
+ * Tool Guide — Static reference for the AI
3
+ *
4
+ * Explains all available tools and how to use them.
5
+ * Update this file whenever tools are added or changed.
6
+ *
7
+ * When `hasSidecars` is false, sidecar-related content (target params,
8
+ * list_sidecars, sidecar section) is omitted entirely so the AI
9
+ * doesn't waste tokens thinking about remote execution.
10
+ */
11
+
12
+ export function buildToolGuide(hasSidecars: boolean): string {
13
+ const lines: string[] = [];
14
+
15
+ lines.push('# Tool Guide');
16
+ lines.push('');
17
+
18
+ // --- Tools ---
19
+ lines.push('## Tools');
20
+ lines.push('');
21
+
22
+ if (hasSidecars) {
23
+ lines.push('These tools work locally by default. To run on a remote machine, pass the `target` parameter with a sidecar name or ID.');
24
+ lines.push('');
25
+ }
26
+
27
+ lines.push('### run_command');
28
+ lines.push('Execute a shell command. Returns stdout, stderr, and exit code.');
29
+ lines.push('- `command` (required): The shell command to run');
30
+ if (hasSidecars) lines.push('- `target`: Sidecar name or ID for remote execution');
31
+ lines.push('- `cwd`: Working directory');
32
+ lines.push('- `timeout`: Timeout in ms (default: 30000)');
33
+ lines.push('');
34
+
35
+ lines.push('### read_file');
36
+ lines.push('Read a file\'s contents as text (max 100KB).');
37
+ lines.push('- `path` (required): File path');
38
+ if (hasSidecars) lines.push('- `target`: Sidecar name or ID for remote execution');
39
+ lines.push('');
40
+
41
+ lines.push('### write_file');
42
+ lines.push('Write content to a file (creates or overwrites).');
43
+ lines.push('- `path` (required): File path');
44
+ lines.push('- `content` (required): Content to write');
45
+ if (hasSidecars) lines.push('- `target`: Sidecar name or ID for remote execution');
46
+ lines.push('');
47
+
48
+ lines.push('### list_directory');
49
+ lines.push('List directory contents with types and sizes.');
50
+ lines.push('- `path` (required): Directory path');
51
+ if (hasSidecars) lines.push('- `target`: Sidecar name or ID for remote execution');
52
+ lines.push('');
53
+
54
+ lines.push('### get_clipboard');
55
+ lines.push('Read the clipboard contents.');
56
+ if (hasSidecars) lines.push('- `target`: Sidecar name or ID for remote execution');
57
+ lines.push('');
58
+
59
+ lines.push('### set_clipboard');
60
+ lines.push('Write text to the clipboard.');
61
+ lines.push('- `content` (required): Text to write');
62
+ if (hasSidecars) lines.push('- `target`: Sidecar name or ID for remote execution');
63
+ lines.push('');
64
+
65
+ lines.push('### capture_screen');
66
+ lines.push('Take a screenshot of the screen. Returns base64-encoded PNG.');
67
+ if (hasSidecars) lines.push('- `target`: Sidecar name or ID for remote execution');
68
+ lines.push('');
69
+
70
+ lines.push('### get_system_info');
71
+ lines.push('Get system information (hostname, OS, architecture, CPU count).');
72
+ if (hasSidecars) lines.push('- `target`: Sidecar name or ID for remote execution');
73
+ lines.push('');
74
+
75
+ // --- Browser ---
76
+ lines.push('## Browser');
77
+ lines.push('');
78
+ lines.push('Control a Chrome browser for web research and interaction. Chrome auto-launches on first use. A persistent profile at ~/.jarvis/browser/profile retains login sessions.');
79
+ lines.push('');
80
+ lines.push('Workflow:');
81
+ lines.push('1. `browser_navigate` to a URL — returns page text + interactive elements with [id] numbers');
82
+ lines.push('2. `browser_click` / `browser_type` to interact using element [id]s');
83
+ lines.push('3. `browser_snapshot` to see the page after an action');
84
+ lines.push('4. `browser_scroll` to reveal content below the fold');
85
+ lines.push('5. `browser_evaluate` for advanced JavaScript interactions');
86
+ lines.push('6. `browser_screenshot` for visual capture');
87
+ lines.push('');
88
+ lines.push('### browser_upload_file');
89
+ lines.push('Upload a file to a file input element (bypasses the native file picker). Use this after clicking an upload/attach button.');
90
+ lines.push('- `file_path` (required): Absolute path to the file');
91
+ lines.push('- `selector`: CSS selector for the file input (default: first input[type="file"])');
92
+ lines.push('');
93
+ lines.push('Rules:');
94
+ lines.push('- For READ-ONLY tasks, `browser_navigate` already returns content. Don\'t snapshot just to read.');
95
+ lines.push('- For INTERACTIVE tasks, snapshot after each action to verify.');
96
+ lines.push('- Fill forms FIRST, verify in snapshot, THEN submit.');
97
+ lines.push('- If an element isn\'t visible, scroll down first.');
98
+ lines.push('- Modern SPAs may need `browser_evaluate` for custom components.');
99
+ lines.push('');
100
+
101
+ // --- Sidecars ---
102
+ if (hasSidecars) {
103
+ lines.push('## Sidecars (Remote Machines)');
104
+ lines.push('');
105
+ lines.push('Sidecars are the user\'s other machines (laptops, servers, desktops) connected to the brain. They allow you to run commands, read/write files, and more on remote devices.');
106
+ lines.push('');
107
+ lines.push('### How to use sidecars');
108
+ lines.push('1. Call `list_sidecars` to see which machines are available and their connection status');
109
+ lines.push('2. Use any compatible tool with the `target` parameter set to the sidecar\'s name or ID');
110
+ lines.push('3. If the sidecar is offline or doesn\'t support the required capability, you\'ll get a clear error');
111
+ lines.push('');
112
+ lines.push('### list_sidecars');
113
+ lines.push('Query live sidecar status. Always call this before targeting a remote machine.');
114
+ lines.push('- `filter`: Optional string to filter by name or ID (case-insensitive)');
115
+ lines.push('- Returns: connection status, hostname, OS, capabilities, last seen time');
116
+ lines.push('');
117
+ lines.push('### Capabilities');
118
+ lines.push('Each sidecar advertises what it can do:');
119
+ lines.push('- `terminal` — supports `run_command`');
120
+ lines.push('- `filesystem` — supports `read_file`, `write_file`, `list_directory`');
121
+ lines.push('- `clipboard` — supports `get_clipboard`, `set_clipboard`');
122
+ lines.push('- `screenshot` — supports `capture_screen`');
123
+ lines.push('- `system_info` — supports `get_system_info`');
124
+ lines.push('- `desktop`, `browser` — supports desktop/browser automation tools');
125
+ lines.push('');
126
+ lines.push('If a capability is listed as unavailable (with a reason), do NOT try to work around it with `run_command`. The required system tool is missing and shell commands will fail the same way.');
127
+ lines.push('');
128
+ lines.push('### Example workflow');
129
+ lines.push('User: "Check disk space on my server"');
130
+ lines.push('1. Call `list_sidecars` → see "home-server" is CONNECTED with terminal capability');
131
+ lines.push('2. Call `run_command` with target="home-server", command="df -h"');
132
+ lines.push('3. Report results to user');
133
+ lines.push('');
134
+ }
135
+
136
+ // --- Desktop ---
137
+ lines.push('## Desktop Automation');
138
+ lines.push('');
139
+ lines.push('Control desktop applications on any platform (Windows, macOS, Linux). Works like browser tools but for native desktop apps. The same tools work on all platforms — the sidecar handles OS-specific details internally.');
140
+ lines.push('');
141
+ lines.push('Workflow:');
142
+ lines.push('1. `desktop_list_windows` to see available windows with PIDs');
143
+ lines.push('2. `desktop_snapshot` to get the UI element tree with [id] numbers (like browser_snapshot)');
144
+ lines.push('3. `desktop_click` / `desktop_type` to interact using element [id]s');
145
+ lines.push('4. `desktop_snapshot` again to verify the result');
146
+ lines.push('');
147
+ lines.push('Tools:');
148
+ lines.push('- `desktop_list_windows` — list all visible windows (titles, PIDs, positions)');
149
+ lines.push('- `desktop_snapshot` — get the UI element tree of a window. Each element has an [id]. Optional `depth` param to control tree depth (default: 8).');
150
+ lines.push('- `desktop_click` — click or interact with an element by [id]. Optional `action` param: click (default), double_click, right_click, invoke, toggle, set_value, get_value, expand, collapse, focus. Optional `value` param for set_value.');
151
+ lines.push('- `desktop_type` — type text into the focused element. Optional `element_id` to click-focus first.');
152
+ lines.push('- `desktop_press_keys` — press key combos (e.g., "ctrl,s", "alt,f4", "enter")');
153
+ lines.push('- `desktop_find_element` — search for elements by property (name, control_type, class_name, automation_id) without scanning the full tree');
154
+ lines.push('- `desktop_launch_app` — launch an application by name or path');
155
+ lines.push('- `desktop_focus_window` — bring a window to the foreground by PID');
156
+ lines.push('- `desktop_screenshot` — visual capture of the desktop or a specific window');
157
+ lines.push('');
158
+ lines.push('Rules:');
159
+ lines.push('- Always `desktop_list_windows` first to get the PID, then `desktop_snapshot` with that PID.');
160
+ lines.push('- After clicking or typing, snapshot again to verify the updated state.');
161
+ lines.push('- Use `desktop_find_element` when you know the element name/type — faster than scanning the full tree.');
162
+ lines.push('- The `action` param on `desktop_click` supports richer interactions on Windows (invoke, toggle, set_value, expand, collapse). On macOS/Linux, only click, double_click, right_click, and focus are supported.');
163
+ lines.push('- `automation_id` in `desktop_find_element` is Windows-only; it is ignored on other platforms.');
164
+ lines.push('');
165
+
166
+ // --- Task Management ---
167
+ lines.push('## Task Management');
168
+ lines.push('');
169
+ lines.push('### manage_goals');
170
+ lines.push('OKR-style goal management (create, list, score, decompose, morning plan, evening review).');
171
+ lines.push('');
172
+ lines.push('### manage_workflow');
173
+ lines.push('Create and run automation workflows from natural language.');
174
+ lines.push('');
175
+ lines.push('### delegate_task');
176
+ lines.push('Send a task to a specialist sub-agent (research analyst, software engineer, etc.). The specialist works independently and returns results.');
177
+ lines.push('');
178
+ lines.push('### manage_agents');
179
+ lines.push('Manage persistent background agents for long-running tasks.');
180
+ lines.push('');
181
+
182
+ // --- Other ---
183
+ lines.push('## Other Tools');
184
+ lines.push('');
185
+ lines.push('### research_queue');
186
+ lines.push('Queue topics for background research during idle time.');
187
+ lines.push('');
188
+ lines.push('### commitments');
189
+ lines.push('Track promises and tasks with due dates.');
190
+ lines.push('');
191
+ lines.push('### content_pipeline');
192
+ lines.push('Manage content items through drafting stages.');
193
+
194
+ return lines.join('\n');
195
+ }
@@ -0,0 +1,36 @@
1
+ export type KPI = {
2
+ name: string;
3
+ metric: string;
4
+ target: string;
5
+ check_interval: string;
6
+ };
7
+
8
+ export type CommunicationStyle = {
9
+ tone: string;
10
+ verbosity: 'concise' | 'detailed' | 'adaptive';
11
+ formality: 'formal' | 'casual' | 'adaptive';
12
+ };
13
+
14
+ export type SubRoleTemplate = {
15
+ role_id: string;
16
+ name: string;
17
+ description: string;
18
+ spawned_by: string;
19
+ reports_to: string;
20
+ max_budget_per_task: number;
21
+ };
22
+
23
+ export type RoleDefinition = {
24
+ id: string;
25
+ name: string;
26
+ description: string;
27
+ responsibilities: string[];
28
+ autonomous_actions: string[];
29
+ approval_required: string[];
30
+ kpis: KPI[];
31
+ communication_style: CommunicationStyle;
32
+ heartbeat_instructions: string;
33
+ sub_roles: SubRoleTemplate[];
34
+ tools: string[];
35
+ authority_level: number; // 1-10
36
+ };
@@ -0,0 +1,200 @@
1
+ /**
2
+ * Utility functions for working with roles
3
+ */
4
+
5
+ import type { RoleDefinition } from './types.ts';
6
+ import type { ActionCategory } from './authority.ts';
7
+ import { canPerform, listAllowedActions } from './authority.ts';
8
+
9
+ /**
10
+ * Find roles that can perform a specific action
11
+ */
12
+ export function findRolesWithPermission(
13
+ roles: Map<string, RoleDefinition>,
14
+ action: ActionCategory
15
+ ): RoleDefinition[] {
16
+ const result: RoleDefinition[] = [];
17
+
18
+ for (const role of roles.values()) {
19
+ if (canPerform(role, action)) {
20
+ result.push(role);
21
+ }
22
+ }
23
+
24
+ return result.sort((a, b) => a.authority_level - b.authority_level);
25
+ }
26
+
27
+ /**
28
+ * Find the least privileged role that can perform an action
29
+ */
30
+ export function findMinimalRoleForAction(
31
+ roles: Map<string, RoleDefinition>,
32
+ action: ActionCategory
33
+ ): RoleDefinition | null {
34
+ const capable = findRolesWithPermission(roles, action);
35
+ return capable.length > 0 ? capable[0]! : null;
36
+ }
37
+
38
+ /**
39
+ * Compare two roles and show permission differences
40
+ */
41
+ export function compareRoles(
42
+ role1: RoleDefinition,
43
+ role2: RoleDefinition
44
+ ): {
45
+ onlyInRole1: ActionCategory[];
46
+ onlyInRole2: ActionCategory[];
47
+ inBoth: ActionCategory[];
48
+ } {
49
+ const actions1 = new Set(listAllowedActions(role1));
50
+ const actions2 = new Set(listAllowedActions(role2));
51
+
52
+ const onlyInRole1: ActionCategory[] = [];
53
+ const onlyInRole2: ActionCategory[] = [];
54
+ const inBoth: ActionCategory[] = [];
55
+
56
+ for (const action of actions1) {
57
+ if (actions2.has(action)) {
58
+ inBoth.push(action);
59
+ } else {
60
+ onlyInRole1.push(action);
61
+ }
62
+ }
63
+
64
+ for (const action of actions2) {
65
+ if (!actions1.has(action)) {
66
+ onlyInRole2.push(action);
67
+ }
68
+ }
69
+
70
+ return { onlyInRole1, onlyInRole2, inBoth };
71
+ }
72
+
73
+ /**
74
+ * Get a summary of role hierarchy based on authority levels
75
+ */
76
+ export function getRoleHierarchy(roles: Map<string, RoleDefinition>): string {
77
+ const sorted = Array.from(roles.values()).sort(
78
+ (a, b) => b.authority_level - a.authority_level
79
+ );
80
+
81
+ const lines: string[] = [];
82
+ let currentLevel = -1;
83
+
84
+ for (const role of sorted) {
85
+ if (role.authority_level !== currentLevel) {
86
+ currentLevel = role.authority_level;
87
+ lines.push(`\nLevel ${currentLevel}:`);
88
+ }
89
+ lines.push(` - ${role.name} (${role.id})`);
90
+ }
91
+
92
+ return lines.join('\n').trim();
93
+ }
94
+
95
+ /**
96
+ * Check if a role can spawn a specific sub-role
97
+ */
98
+ export function canSpawnRole(
99
+ role: RoleDefinition,
100
+ subRoleId: string
101
+ ): boolean {
102
+ return role.sub_roles.some(sr => sr.role_id === subRoleId);
103
+ }
104
+
105
+ /**
106
+ * Get all roles that can spawn a specific role
107
+ */
108
+ export function findSpawnersOfRole(
109
+ roles: Map<string, RoleDefinition>,
110
+ targetRoleId: string
111
+ ): RoleDefinition[] {
112
+ const spawners: RoleDefinition[] = [];
113
+
114
+ for (const role of roles.values()) {
115
+ if (canSpawnRole(role, targetRoleId)) {
116
+ spawners.push(role);
117
+ }
118
+ }
119
+
120
+ return spawners;
121
+ }
122
+
123
+ /**
124
+ * Validate role hierarchy (check for circular dependencies)
125
+ */
126
+ export function validateRoleHierarchy(
127
+ roles: Map<string, RoleDefinition>
128
+ ): { valid: boolean; errors: string[] } {
129
+ const errors: string[] = [];
130
+
131
+ for (const [id, role] of roles) {
132
+ // Check if sub-roles exist
133
+ for (const subRole of role.sub_roles) {
134
+ if (!roles.has(subRole.role_id)) {
135
+ errors.push(
136
+ `Role '${id}' references non-existent sub-role '${subRole.role_id}'`
137
+ );
138
+ }
139
+
140
+ // Check for self-spawning
141
+ if (subRole.role_id === id) {
142
+ errors.push(`Role '${id}' attempts to spawn itself`);
143
+ }
144
+
145
+ // Check authority levels (parent should have higher authority)
146
+ const subRoleDef = roles.get(subRole.role_id);
147
+ if (subRoleDef && subRoleDef.authority_level > role.authority_level) {
148
+ errors.push(
149
+ `Role '${id}' (level ${role.authority_level}) attempts to spawn ` +
150
+ `'${subRole.role_id}' (level ${subRoleDef.authority_level}) with higher authority`
151
+ );
152
+ }
153
+ }
154
+ }
155
+
156
+ return {
157
+ valid: errors.length === 0,
158
+ errors,
159
+ };
160
+ }
161
+
162
+ /**
163
+ * Get statistics about a role collection
164
+ */
165
+ export function getRoleStats(roles: Map<string, RoleDefinition>): {
166
+ totalRoles: number;
167
+ averageAuthorityLevel: number;
168
+ totalTools: number;
169
+ totalKPIs: number;
170
+ rolesWithSubRoles: number;
171
+ authorityDistribution: Record<number, number>;
172
+ } {
173
+ let totalAuthority = 0;
174
+ let totalTools = 0;
175
+ let totalKPIs = 0;
176
+ let rolesWithSubRoles = 0;
177
+ const authorityDistribution: Record<number, number> = {};
178
+
179
+ for (const role of roles.values()) {
180
+ totalAuthority += role.authority_level;
181
+ totalTools += role.tools.length;
182
+ totalKPIs += role.kpis.length;
183
+
184
+ if (role.sub_roles.length > 0) {
185
+ rolesWithSubRoles++;
186
+ }
187
+
188
+ authorityDistribution[role.authority_level] =
189
+ (authorityDistribution[role.authority_level] || 0) + 1;
190
+ }
191
+
192
+ return {
193
+ totalRoles: roles.size,
194
+ averageAuthorityLevel: roles.size > 0 ? totalAuthority / roles.size : 0,
195
+ totalTools,
196
+ totalKPIs,
197
+ rolesWithSubRoles,
198
+ authorityDistribution,
199
+ };
200
+ }
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Google OAuth2 Setup Script
3
+ *
4
+ * Interactive CLI to authenticate JARVIS with Google APIs.
5
+ * Opens browser to Google consent screen, handles callback,
6
+ * and saves tokens to ~/.jarvis/google-tokens.json.
7
+ *
8
+ * Usage: bun run src/scripts/google-setup.ts
9
+ */
10
+
11
+ import { GoogleAuth } from '../integrations/google-auth.ts';
12
+ import { loadConfig } from '../config/loader.ts';
13
+
14
+ const SCOPES = [
15
+ 'https://www.googleapis.com/auth/gmail.readonly',
16
+ 'https://www.googleapis.com/auth/calendar.readonly',
17
+ ];
18
+
19
+ async function main() {
20
+ console.log('');
21
+ console.log('=== Google OAuth2 Setup for JARVIS ===');
22
+ console.log('');
23
+
24
+ // Load config to get client_id / client_secret
25
+ const config = await loadConfig();
26
+
27
+ let clientId = config.google?.client_id ?? '';
28
+ let clientSecret = config.google?.client_secret ?? '';
29
+
30
+ if (!clientId || !clientSecret) {
31
+ console.log('No Google OAuth credentials found in config.yaml.');
32
+ console.log('');
33
+ console.log('Add the following to your ~/.jarvis/config.yaml:');
34
+ console.log('');
35
+ console.log('google:');
36
+ console.log(' client_id: "your-client-id.apps.googleusercontent.com"');
37
+ console.log(' client_secret: "your-client-secret"');
38
+ console.log('');
39
+ console.log('To get credentials:');
40
+ console.log(' 1. Go to https://console.cloud.google.com/apis/credentials');
41
+ console.log(' 2. Create an OAuth2 client ID (Web application)');
42
+ console.log(' 3. Add http://localhost:3142/api/auth/google/callback as a redirect URI');
43
+ console.log(' 4. Copy client_id and client_secret into config.yaml');
44
+ console.log('');
45
+
46
+ // Try reading from stdin
47
+ const rl = require('readline').createInterface({
48
+ input: process.stdin,
49
+ output: process.stdout,
50
+ });
51
+
52
+ const ask = (q: string): Promise<string> =>
53
+ new Promise((resolve) => rl.question(q, resolve));
54
+
55
+ clientId = (await ask('Client ID (or press Enter to abort): ')).trim();
56
+ if (!clientId) {
57
+ console.log('Aborted.');
58
+ rl.close();
59
+ process.exit(1);
60
+ }
61
+
62
+ clientSecret = (await ask('Client Secret: ')).trim();
63
+ if (!clientSecret) {
64
+ console.log('Aborted.');
65
+ rl.close();
66
+ process.exit(1);
67
+ }
68
+
69
+ rl.close();
70
+ }
71
+
72
+ const auth = new GoogleAuth(clientId, clientSecret);
73
+
74
+ // Check if already authenticated
75
+ if (auth.isAuthenticated()) {
76
+ console.log('Already authenticated! Tokens exist at ~/.jarvis/google-tokens.json');
77
+ console.log('To re-authenticate, delete that file and run this again.');
78
+ process.exit(0);
79
+ }
80
+
81
+ const authUrl = auth.getAuthUrl(SCOPES);
82
+
83
+ console.log('');
84
+ console.log('Opening browser for Google authorization...');
85
+ console.log('');
86
+ console.log('If the browser does not open, visit this URL:');
87
+ console.log(authUrl);
88
+ console.log('');
89
+
90
+ // Try to open browser
91
+ try {
92
+ const opener = process.platform === 'darwin'
93
+ ? 'open'
94
+ : process.platform === 'win32'
95
+ ? 'start'
96
+ : 'xdg-open';
97
+ Bun.spawn([opener, authUrl], { stdout: 'ignore', stderr: 'ignore' });
98
+ } catch {
99
+ // Ignore — user can open manually
100
+ }
101
+
102
+ // Start temporary HTTP server to receive the callback
103
+ console.log('Waiting for authorization callback on port 3142...');
104
+ console.log('');
105
+
106
+ const server = Bun.serve({
107
+ port: 3142,
108
+ async fetch(req) {
109
+ const url = new URL(req.url);
110
+
111
+ if (url.pathname === '/api/auth/google/callback') {
112
+ const code = url.searchParams.get('code');
113
+ const error = url.searchParams.get('error');
114
+
115
+ if (error) {
116
+ console.error('Authorization denied:', error);
117
+ setTimeout(() => {
118
+ server.stop();
119
+ process.exit(1);
120
+ }, 500);
121
+ return new Response(
122
+ '<html><body><h1>Authorization Denied</h1><p>You can close this tab.</p></body></html>',
123
+ { headers: { 'Content-Type': 'text/html' } }
124
+ );
125
+ }
126
+
127
+ if (!code) {
128
+ return new Response('Missing code', { status: 400 });
129
+ }
130
+
131
+ try {
132
+ const tokens = await auth.exchangeCode(code);
133
+ console.log('Authorization successful!');
134
+ console.log(`Access token: ${tokens.access_token.slice(0, 20)}...`);
135
+ console.log(`Refresh token: ${tokens.refresh_token.slice(0, 20)}...`);
136
+ console.log(`Tokens saved to ~/.jarvis/google-tokens.json`);
137
+
138
+ setTimeout(() => {
139
+ server.stop();
140
+ process.exit(0);
141
+ }, 500);
142
+
143
+ return new Response(
144
+ '<html><body><h1>JARVIS Google Authorization Complete!</h1><p>Tokens saved. You can close this tab.</p></body></html>',
145
+ { headers: { 'Content-Type': 'text/html' } }
146
+ );
147
+ } catch (err) {
148
+ console.error('Token exchange failed:', err);
149
+ setTimeout(() => {
150
+ server.stop();
151
+ process.exit(1);
152
+ }, 500);
153
+ return new Response(
154
+ `<html><body><h1>Token Exchange Failed</h1><pre>${err}</pre></body></html>`,
155
+ { headers: { 'Content-Type': 'text/html' }, status: 500 }
156
+ );
157
+ }
158
+ }
159
+
160
+ return new Response('Not found', { status: 404 });
161
+ },
162
+ });
163
+ }
164
+
165
+ main().catch((err) => {
166
+ console.error('Setup failed:', err);
167
+ process.exit(1);
168
+ });