@agentprojectcontext/apx 1.80.2 → 1.89.1

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 (838) hide show
  1. package/package.json +9 -8
  2. package/skills/apc-context/SKILL.md +14 -7
  3. package/skills/apx/SKILL.md +62 -2
  4. package/skills/apx-mcp/SKILL.md +42 -15
  5. package/src/core/agent/a2a/peers.js +161 -0
  6. package/src/core/agent/a2a/reply.js +379 -27
  7. package/src/core/agent/abort.js +25 -0
  8. package/src/core/agent/agent-model.js +58 -0
  9. package/src/core/agent/agent-tools.js +101 -0
  10. package/src/core/agent/author-line.js +110 -0
  11. package/src/core/agent/build-agent-system.js +52 -18
  12. package/src/core/agent/channels/voice-context.js +17 -2
  13. package/src/core/agent/closing-floor.js +117 -0
  14. package/src/core/agent/constants.js +119 -11
  15. package/src/core/agent/engine-call.js +56 -0
  16. package/src/core/agent/group/run-group-turn.js +218 -0
  17. package/src/core/agent/group/turn-resolver.js +165 -0
  18. package/src/core/agent/judge.js +138 -11
  19. package/src/core/agent/loop/side-effects.js +106 -3
  20. package/src/core/agent/memory.js +31 -18
  21. package/src/core/agent/model-capabilities.js +47 -0
  22. package/src/core/agent/model-router.js +11 -40
  23. package/src/core/agent/prompt-builder.js +47 -0
  24. package/src/core/agent/prompts/channels/a2a.md +12 -0
  25. package/src/core/agent/prompts/channels/code.md +3 -1
  26. package/src/core/agent/prompts/channels/telegram.md +2 -0
  27. package/src/core/agent/prompts/channels/web_code.md +1 -1
  28. package/src/core/agent/prompts/channels/whatsapp.md +37 -0
  29. package/src/core/agent/prompts/core/agent-base.md +2 -0
  30. package/src/core/agent/prompts/discipline/action.md +1 -0
  31. package/src/core/agent/prompts/discipline/two-segment.md +2 -1
  32. package/src/core/agent/prompts/modes/mobility.md +36 -0
  33. package/src/core/agent/retry.js +42 -0
  34. package/src/core/agent/run-agent.js +322 -25
  35. package/src/core/agent/run-turn.js +253 -0
  36. package/src/core/agent/self-memory.js +18 -52
  37. package/src/core/agent/skills/agent-skills.js +118 -0
  38. package/src/core/agent/skills/catalog.js +1 -1
  39. package/src/core/agent/skills/declared.js +13 -0
  40. package/src/core/agent/skills/index-store.js +8 -1
  41. package/src/core/agent/skills/inspector.js +20 -3
  42. package/src/core/agent/skills/loader.js +18 -3
  43. package/src/core/agent/skills/media.js +121 -0
  44. package/src/core/agent/skills/origin.js +61 -0
  45. package/src/core/agent/skills/sections.js +136 -0
  46. package/src/core/agent/super-agent.js +54 -14
  47. package/src/core/agent/tools/handlers/_calendar.js +50 -0
  48. package/src/core/agent/tools/handlers/add-mcp.js +103 -0
  49. package/src/core/agent/tools/handlers/asana-create-task.js +3 -1
  50. package/src/core/agent/tools/handlers/attach-media.js +56 -0
  51. package/src/core/agent/tools/handlers/calendar-create-event.js +38 -0
  52. package/src/core/agent/tools/handlers/calendar-find-slot.js +39 -0
  53. package/src/core/agent/tools/handlers/calendar-list-events.js +39 -0
  54. package/src/core/agent/tools/handlers/calendar-update-event.js +35 -0
  55. package/src/core/agent/tools/handlers/call-agent.js +14 -6
  56. package/src/core/agent/tools/handlers/call-runtime.js +27 -49
  57. package/src/core/agent/tools/handlers/comment-task.js +78 -0
  58. package/src/core/agent/tools/handlers/complete-task.js +60 -0
  59. package/src/core/agent/tools/handlers/configure-agent.js +70 -0
  60. package/src/core/agent/tools/handlers/create-agent.js +68 -0
  61. package/src/core/agent/tools/handlers/create-task.js +41 -3
  62. package/src/core/agent/tools/handlers/import-agent.js +5 -5
  63. package/src/core/agent/tools/handlers/list-mcp-tools.js +83 -0
  64. package/src/core/agent/tools/handlers/list-routines.js +46 -0
  65. package/src/core/agent/tools/handlers/list-tasks.js +8 -1
  66. package/src/core/agent/tools/handlers/mark-commitment.js +57 -0
  67. package/src/core/agent/tools/handlers/read-skill.js +64 -0
  68. package/src/core/agent/tools/handlers/remember-routine.js +2 -8
  69. package/src/core/agent/tools/handlers/remember.js +82 -6
  70. package/src/core/agent/tools/handlers/remove-agent.js +42 -0
  71. package/src/core/agent/tools/handlers/run-routine.js +94 -0
  72. package/src/core/agent/tools/handlers/run-shell.js +44 -2
  73. package/src/core/agent/tools/handlers/send-telegram.js +41 -19
  74. package/src/core/agent/tools/handlers/set-agent-prompt.js +44 -0
  75. package/src/core/agent/tools/handlers/view-media.js +69 -0
  76. package/src/core/agent/tools/handlers/write-agent-memory.js +52 -0
  77. package/src/core/agent/tools/helpers.js +36 -4
  78. package/src/core/agent/tools/names.js +64 -0
  79. package/src/core/agent/tools/registry-bridge.js +24 -1
  80. package/src/core/agent/tools/registry.js +79 -0
  81. package/src/core/agent/tools/tool-call-parser.js +136 -13
  82. package/src/core/agent/vision-bridge.js +69 -0
  83. package/src/core/apc/agent-identity.js +74 -0
  84. package/src/core/apc/agent-rename-refs.js +187 -0
  85. package/src/core/apc/agent-write.js +312 -0
  86. package/src/core/apc/agents-vault.js +1 -1
  87. package/src/core/apc/blob-keys.js +42 -0
  88. package/src/core/apc/frontmatter.js +166 -10
  89. package/src/core/apc/parser.js +33 -83
  90. package/src/core/apc/paths.js +4 -6
  91. package/src/core/apc/project-memory.js +44 -0
  92. package/src/core/apc/projects-helpers.js +33 -0
  93. package/src/core/apc/scaffold.js +36 -16
  94. package/src/core/channels/telegram/ask-callbacks.js +103 -0
  95. package/src/core/channels/telegram/dispatch.js +154 -30
  96. package/src/core/channels/telegram/helpers.js +59 -7
  97. package/src/core/channels/telegram/inbound/audio.js +26 -30
  98. package/src/core/channels/telegram/inbound/file.js +22 -32
  99. package/src/core/channels/telegram/inbound/photo.js +24 -28
  100. package/src/core/channels/telegram/progress-gate.js +76 -0
  101. package/src/core/channels/telegram/reply.js +151 -43
  102. package/src/core/channels/telegram/voice-note.js +150 -0
  103. package/src/core/config/index.js +53 -54
  104. package/src/core/config/paths.js +117 -31
  105. package/src/core/config/redact.js +89 -4
  106. package/src/core/config/secret-values.js +2 -4
  107. package/src/core/constants/actors.js +5 -0
  108. package/src/core/constants/channels.js +3 -1
  109. package/src/core/constants/task-categories.js +73 -0
  110. package/src/core/constants/task-fields.js +28 -0
  111. package/src/core/engines/_globs.js +33 -0
  112. package/src/core/engines/anthropic.js +19 -1
  113. package/src/core/engines/catalog.js +20 -0
  114. package/src/core/engines/gemini.js +84 -16
  115. package/src/core/engines/index.js +19 -3
  116. package/src/core/engines/mock.js +145 -1
  117. package/src/core/engines/openai-compatible.js +150 -15
  118. package/src/core/engines/presets.js +36 -9
  119. package/src/core/engines/zen.js +131 -0
  120. package/src/core/events/bus.js +140 -0
  121. package/src/core/events/mascot-notify.js +156 -0
  122. package/src/core/http-tools/browser.js +366 -36
  123. package/src/core/http-tools/catalog.js +206 -22
  124. package/src/core/http-tools/grep.js +62 -7
  125. package/src/core/http-tools/registry.js +3 -1
  126. package/src/core/i18n/en.js +34 -3
  127. package/src/core/i18n/es.js +36 -4
  128. package/src/core/i18n/index.js +5 -5
  129. package/src/core/i18n/pt.js +32 -3
  130. package/src/core/identity/self.js +14 -1
  131. package/src/core/images/engines/a1111.js +219 -0
  132. package/src/core/images/engines/index.js +187 -0
  133. package/src/core/images/engines/mock.js +74 -0
  134. package/src/core/images/engines/openai.js +130 -0
  135. package/src/core/images/engines/sdcpp.js +204 -0
  136. package/src/core/images/engines/shared.js +218 -0
  137. package/src/core/images/generate.js +260 -0
  138. package/src/core/integrations/catalog.js +8 -3
  139. package/src/core/integrations/plugins/_google-oauth.js +179 -0
  140. package/src/core/integrations/plugins/asana.js +7 -3
  141. package/src/core/integrations/plugins/calendar.js +404 -0
  142. package/src/core/integrations/store.js +2 -0
  143. package/src/core/memory/broker.js +16 -1
  144. package/src/core/memory/compactor.js +19 -3
  145. package/src/core/memory/consolidate.js +2 -2
  146. package/src/core/memory/dated-log.js +66 -0
  147. package/src/core/memory/embed-engines/custom.js +59 -0
  148. package/src/core/memory/embed-engines/gemini.js +9 -3
  149. package/src/core/memory/embed-engines/index.js +87 -15
  150. package/src/core/memory/embeddings.js +52 -24
  151. package/src/core/memory/index.js +13 -3
  152. package/src/core/memory/indexer.js +83 -27
  153. package/src/core/memory/prune.js +182 -0
  154. package/src/core/memory/store.js +22 -0
  155. package/src/core/memory/summarizer.js +72 -8
  156. package/src/core/mobility/answer.js +80 -0
  157. package/src/core/mobility/geofence.js +667 -0
  158. package/src/core/mobility/osm-route.js +282 -0
  159. package/src/core/mobility/preferences.js +91 -0
  160. package/src/core/mobility/state.js +245 -0
  161. package/src/core/mobility/trip-event.js +384 -0
  162. package/src/core/net/tailscale.js +168 -0
  163. package/src/core/profiles/bundled/secretary/PROFILE.md +32 -42
  164. package/src/core/profiles/bundled/secretary/config.schema.es.json +68 -0
  165. package/src/core/profiles/bundled/secretary/config.schema.json +30 -2
  166. package/src/core/profiles/bundled/secretary/profile.json +3 -1
  167. package/src/core/profiles/bundled/secretary/routines/a2a-sweep.json +20 -0
  168. package/src/core/profiles/bundled/secretary/routines/day-close.json +4 -1
  169. package/src/core/profiles/bundled/secretary/routines/day-open.json +7 -1
  170. package/src/core/profiles/bundled/secretary/routines/watch.json +13 -2
  171. package/src/core/profiles/lifecycle.js +243 -19
  172. package/src/core/profiles/paths.js +12 -0
  173. package/src/core/profiles/store.js +47 -0
  174. package/src/core/routines/active-runs.js +213 -0
  175. package/src/core/routines/delivery.js +612 -0
  176. package/src/core/routines/header.js +88 -0
  177. package/src/core/routines/index.js +26 -0
  178. package/src/core/routines/run-log.js +78 -0
  179. package/src/core/routines/runner.js +629 -66
  180. package/src/core/routines/signals.js +75 -0
  181. package/src/core/runtime-skills/apc-context/SKILL.md +14 -7
  182. package/src/core/runtime-skills/apx/SKILL.md +93 -1
  183. package/src/core/runtime-skills/apx-agency-agents/SKILL.md +2 -2
  184. package/src/core/runtime-skills/apx-agent/SKILL.md +134 -19
  185. package/src/core/runtime-skills/apx-commitment/SKILL.md +134 -0
  186. package/src/core/runtime-skills/apx-image/SKILL.md +60 -0
  187. package/src/core/runtime-skills/apx-integrations/SKILL.md +82 -0
  188. package/src/core/runtime-skills/apx-mcp/SKILL.md +45 -14
  189. package/src/core/runtime-skills/apx-mcp-builder/SKILL.md +4 -4
  190. package/src/core/runtime-skills/apx-profile/SKILL.md +27 -2
  191. package/src/core/runtime-skills/apx-project/SKILL.md +23 -2
  192. package/src/core/runtime-skills/apx-routine/SKILL.md +40 -17
  193. package/src/core/runtime-skills/apx-runtime/SKILL.md +124 -14
  194. package/src/core/runtime-skills/apx-sessions/SKILL.md +7 -6
  195. package/src/core/runtime-skills/apx-skill-builder/SKILL.md +15 -13
  196. package/src/core/runtime-skills/apx-task/SKILL.md +79 -26
  197. package/src/core/runtime-skills/apx-telegram/SKILL.md +12 -12
  198. package/src/core/runtime-skills/apx-transcribe/SKILL.md +56 -0
  199. package/src/core/runtime-skills/apx-voice/SKILL.md +27 -8
  200. package/src/core/runtime-skills/claude-code/SKILL.md +8 -0
  201. package/src/core/runtime-skills/openrouter/SKILL.md +8 -2
  202. package/src/core/runtimes/_spawn.js +9 -1
  203. package/src/core/runtimes/claude-code.js +11 -2
  204. package/src/core/runtimes/codex.js +44 -10
  205. package/src/core/runtimes/index.js +17 -2
  206. package/src/core/runtimes/opencode.js +88 -9
  207. package/src/core/runtimes/outcome.js +119 -0
  208. package/src/core/sessions/index.js +193 -1
  209. package/src/core/stores/agent-inbox.js +109 -23
  210. package/src/core/stores/code-sessions.js +21 -0
  211. package/src/core/stores/commitments.js +27 -3
  212. package/src/core/stores/conversations.js +220 -20
  213. package/src/core/stores/deliveries.js +177 -0
  214. package/src/core/stores/media-archive.js +228 -0
  215. package/src/core/stores/messages.js +1096 -112
  216. package/src/core/stores/organization.js +34 -0
  217. package/src/core/stores/project-memory.js +71 -0
  218. package/src/core/stores/routine-memory.js +16 -8
  219. package/src/core/stores/routines.js +27 -49
  220. package/src/core/stores/sessions.js +4 -8
  221. package/src/core/stores/tasks.js +212 -18
  222. package/src/core/stores/turn-record.js +209 -0
  223. package/src/core/tasks/columns.js +136 -0
  224. package/src/core/tasks/comment-turn.js +258 -0
  225. package/src/core/util/time.js +13 -0
  226. package/src/core/voice/engines/index.js +54 -1
  227. package/src/core/voice/engines/openai.js +50 -4
  228. package/src/core/voice/opus.js +67 -0
  229. package/src/core/voice/pronounceable.js +43 -0
  230. package/src/core/voice/transcription.js +4 -0
  231. package/src/core/voice/tts.js +114 -24
  232. package/src/host/daemon/active-turns.js +188 -0
  233. package/src/host/daemon/api/admin-config.js +9 -0
  234. package/src/host/daemon/api/agents.js +99 -90
  235. package/src/host/daemon/api/artifact-preview.js +7 -6
  236. package/src/host/daemon/api/artifacts.js +3 -2
  237. package/src/host/daemon/api/code.js +55 -9
  238. package/src/host/daemon/api/commitments.js +11 -0
  239. package/src/host/daemon/api/confirm.js +3 -2
  240. package/src/host/daemon/api/conversations.js +543 -35
  241. package/src/host/daemon/api/deck.js +9 -8
  242. package/src/host/daemon/api/deliveries.js +33 -0
  243. package/src/host/daemon/api/desktop.js +5 -4
  244. package/src/host/daemon/api/embeddings.js +15 -6
  245. package/src/host/daemon/api/engines.js +59 -8
  246. package/src/host/daemon/api/exec.js +437 -121
  247. package/src/host/daemon/api/groups.js +215 -0
  248. package/src/host/daemon/api/images.js +107 -0
  249. package/src/host/daemon/api/inbox.js +123 -2
  250. package/src/host/daemon/api/integrations.js +64 -2
  251. package/src/host/daemon/api/mcps.js +7 -6
  252. package/src/host/daemon/api/media.js +283 -0
  253. package/src/host/daemon/api/mobility.js +177 -0
  254. package/src/host/daemon/api/net.js +182 -0
  255. package/src/host/daemon/api/pairing.js +38 -5
  256. package/src/host/daemon/api/profiles.js +30 -2
  257. package/src/host/daemon/api/routines.js +36 -4
  258. package/src/host/daemon/api/runtimes.js +74 -39
  259. package/src/host/daemon/api/sessions-search.js +7 -2
  260. package/src/host/daemon/api/sessions.js +44 -2
  261. package/src/host/daemon/api/shared.js +127 -20
  262. package/src/host/daemon/api/skills.js +11 -4
  263. package/src/host/daemon/api/super-agent.js +384 -53
  264. package/src/host/daemon/api/tasks.js +180 -10
  265. package/src/host/daemon/api/telegram.js +11 -10
  266. package/src/host/daemon/api/thread-faces.js +159 -0
  267. package/src/host/daemon/api/top-level.js +3 -3
  268. package/src/host/daemon/api/transcribe.js +11 -10
  269. package/src/host/daemon/api/tts.js +97 -4
  270. package/src/host/daemon/api/turn-abort.js +23 -0
  271. package/src/host/daemon/api/turns.js +49 -0
  272. package/src/host/daemon/api/voice.js +5 -4
  273. package/src/host/daemon/api/web.js +98 -0
  274. package/src/host/daemon/api.js +39 -0
  275. package/src/host/daemon/delivery-sweep.js +58 -0
  276. package/src/host/daemon/desktop-ws.js +5 -23
  277. package/src/host/daemon/events-ws.js +273 -0
  278. package/src/host/daemon/index.js +59 -15
  279. package/src/host/daemon/plugins/desktop/index.js +17 -4
  280. package/src/host/daemon/plugins/telegram/index.js +78 -40
  281. package/src/host/daemon/pty-bridge.py +99 -0
  282. package/src/host/daemon/routines-scheduler.js +1 -0
  283. package/src/host/daemon/smoke.js +1 -2
  284. package/src/host/daemon/terminal-ws.js +132 -0
  285. package/src/host/daemon/tts-keepwarm.js +87 -0
  286. package/src/host/daemon/wakeup.js +11 -6
  287. package/src/host/daemon/whisper-server.js +44 -0
  288. package/src/host/daemon/whisper-server.py +70 -13
  289. package/src/host/daemon/ws-auth.js +28 -0
  290. package/src/interfaces/android/app/build.gradle +42 -0
  291. package/src/interfaces/android/app/proguard-rules.pro +4 -0
  292. package/src/interfaces/android/app/src/main/AndroidManifest.xml +139 -0
  293. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/AlertScreen.java +139 -0
  294. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/AndroidAutoDetector.java +106 -0
  295. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/ApxCarAppService.java +57 -0
  296. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/ApxPreferences.java +165 -0
  297. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/CarAlertStore.java +84 -0
  298. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/CarMessageActionReceiver.java +47 -0
  299. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/CarMessageNotification.java +152 -0
  300. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/DaemonAddress.java +35 -0
  301. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/DaemonClient.java +339 -0
  302. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/DeviceLocation.java +38 -0
  303. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/ErrandScreen.java +127 -0
  304. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MainActivity.java +872 -0
  305. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MapsNavigationDetector.java +63 -0
  306. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MapsNavigationListenerService.java +453 -0
  307. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MapsShareIntentParser.java +93 -0
  308. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MascotBlobCatalog.java +66 -0
  309. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MascotOverlayService.java +448 -0
  310. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MascotView.java +249 -0
  311. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MessageFrameParser.java +240 -0
  312. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/NotifyChannels.java +69 -0
  313. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/ProximityActionReceiver.java +78 -0
  314. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/ProximityNotification.java +161 -0
  315. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/StartupReceiver.java +57 -0
  316. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/TravelEventGate.java +62 -0
  317. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/TravelStatusBanner.java +116 -0
  318. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/TripLocationService.java +272 -0
  319. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/TripPlacesSheet.java +203 -0
  320. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/TripScreen.java +182 -0
  321. package/src/interfaces/android/app/src/main/res/drawable/app_background.xml +12 -0
  322. package/src/interfaces/android/app/src/main/res/drawable/ic_apx_app.xml +10 -0
  323. package/src/interfaces/android/app/src/main/res/drawable/ic_apx_launcher_foreground.xml +12 -0
  324. package/src/interfaces/android/app/src/main/res/drawable/ic_apx_notification.xml +22 -0
  325. package/src/interfaces/android/app/src/main/res/drawable/ic_trip_car.xml +37 -0
  326. package/src/interfaces/android/app/src/main/res/drawable-nodpi/apx_logo.png +0 -0
  327. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_amatista.png +0 -0
  328. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_aqua.png +0 -0
  329. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_brasa.png +0 -0
  330. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_campana.png +0 -0
  331. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_caracol.png +0 -0
  332. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_carbon.png +0 -0
  333. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_cobalto.png +0 -0
  334. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_cometa.png +0 -0
  335. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_coral.png +0 -0
  336. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_cubi.png +0 -0
  337. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_eclipse.png +0 -0
  338. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_faro.png +0 -0
  339. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_gajo.png +0 -0
  340. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_iris.png +0 -0
  341. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_kiwi.png +0 -0
  342. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_laguna.png +0 -0
  343. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_lila.png +0 -0
  344. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_menta.png +0 -0
  345. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_nimbo.png +0 -0
  346. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_noche.png +0 -0
  347. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_onyx.png +0 -0
  348. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_orbita.png +0 -0
  349. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_ovni.png +0 -0
  350. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_papa.png +0 -0
  351. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_parche.png +0 -0
  352. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_peon.png +0 -0
  353. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_perla.png +0 -0
  354. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_pino.png +0 -0
  355. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_quad.png +0 -0
  356. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_rubi.png +0 -0
  357. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_saturno.png +0 -0
  358. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_trebol.png +0 -0
  359. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_trino.png +0 -0
  360. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_volcan.png +0 -0
  361. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_zafiro.png +0 -0
  362. package/src/interfaces/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +5 -0
  363. package/src/interfaces/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +5 -0
  364. package/src/interfaces/android/app/src/main/res/raw/apx_notification.mp3 +0 -0
  365. package/src/interfaces/android/app/src/main/res/values/colors.xml +4 -0
  366. package/src/interfaces/android/app/src/main/res/values/strings.xml +25 -0
  367. package/src/interfaces/android/app/src/main/res/values/styles.xml +10 -0
  368. package/src/interfaces/android/app/src/main/res/values-v31/styles.xml +14 -0
  369. package/src/interfaces/android/app/src/main/res/xml/automotive_app_desc.xml +9 -0
  370. package/src/interfaces/android/app/src/main/res/xml/network_security_config.xml +10 -0
  371. package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/AndroidAutoDetectorTest.java +85 -0
  372. package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/CarAlertStoreTest.java +104 -0
  373. package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/DaemonAddressTest.java +23 -0
  374. package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/MapsNavigationDetectorTest.java +69 -0
  375. package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/MapsShareIntentParserTest.java +31 -0
  376. package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/MessageFrameParserTest.java +180 -0
  377. package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/TravelEventGateTest.java +64 -0
  378. package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/TripPlacesSheetTest.java +66 -0
  379. package/src/interfaces/android/build.gradle +3 -0
  380. package/src/interfaces/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  381. package/src/interfaces/android/gradle/wrapper/gradle-wrapper.properties +9 -0
  382. package/src/interfaces/android/gradle.properties +3 -0
  383. package/src/interfaces/android/gradlew +248 -0
  384. package/src/interfaces/android/gradlew.bat +82 -0
  385. package/src/interfaces/android/settings.gradle +18 -0
  386. package/src/interfaces/cli/commands/a2a.js +145 -4
  387. package/src/interfaces/cli/commands/agent.js +247 -22
  388. package/src/interfaces/cli/commands/code.js +1 -1
  389. package/src/interfaces/cli/commands/commitment.js +5 -0
  390. package/src/interfaces/cli/commands/config.js +85 -6
  391. package/src/interfaces/cli/commands/exec.js +90 -1
  392. package/src/interfaces/cli/commands/image.js +314 -0
  393. package/src/interfaces/cli/commands/mcp.js +87 -23
  394. package/src/interfaces/cli/commands/memory.js +35 -22
  395. package/src/interfaces/cli/commands/panel.js +94 -0
  396. package/src/interfaces/cli/commands/profile.js +14 -0
  397. package/src/interfaces/cli/commands/project.js +29 -0
  398. package/src/interfaces/cli/commands/routine.js +45 -10
  399. package/src/interfaces/cli/commands/runtime.js +30 -7
  400. package/src/interfaces/cli/commands/session.js +90 -38
  401. package/src/interfaces/cli/commands/sessions.js +35 -2
  402. package/src/interfaces/cli/commands/skills.js +15 -9
  403. package/src/interfaces/cli/commands/status.js +2 -3
  404. package/src/interfaces/cli/commands/task.js +54 -5
  405. package/src/interfaces/cli/commands/telegram.js +12 -4
  406. package/src/interfaces/cli/commands/transcribe.js +177 -0
  407. package/src/interfaces/cli/help/index.js +311 -72
  408. package/src/interfaces/cli/http.js +61 -13
  409. package/src/interfaces/cli/index.js +1 -1
  410. package/src/interfaces/cli/routes/agent.js +5 -4
  411. package/src/interfaces/cli/routes/commitment.js +3 -2
  412. package/src/interfaces/cli/routes/config.js +7 -2
  413. package/src/interfaces/cli/routes/image.js +11 -0
  414. package/src/interfaces/cli/routes/index.js +2 -0
  415. package/src/interfaces/cli/routes/log.js +1 -1
  416. package/src/interfaces/cli/routes/memory.js +3 -2
  417. package/src/interfaces/cli/routes/panel.js +15 -2
  418. package/src/interfaces/cli/routes/profile.js +3 -2
  419. package/src/interfaces/cli/routes/transcribe.js +10 -0
  420. package/src/interfaces/cli/stdin.js +29 -0
  421. package/src/interfaces/desktop/assets/blobs/amatista.png +0 -0
  422. package/src/interfaces/desktop/assets/blobs/aqua.png +0 -0
  423. package/src/interfaces/desktop/assets/blobs/brasa.png +0 -0
  424. package/src/interfaces/desktop/assets/blobs/campana.png +0 -0
  425. package/src/interfaces/desktop/assets/blobs/caracol.png +0 -0
  426. package/src/interfaces/desktop/assets/blobs/carbon.png +0 -0
  427. package/src/interfaces/desktop/assets/blobs/cobalto.png +0 -0
  428. package/src/interfaces/desktop/assets/blobs/cometa.png +0 -0
  429. package/src/interfaces/desktop/assets/blobs/coral.png +0 -0
  430. package/src/interfaces/desktop/assets/blobs/cubi.png +0 -0
  431. package/src/interfaces/desktop/assets/blobs/eclipse.png +0 -0
  432. package/src/interfaces/desktop/assets/blobs/faro.png +0 -0
  433. package/src/interfaces/desktop/assets/blobs/gajo.png +0 -0
  434. package/src/interfaces/desktop/assets/blobs/iris.png +0 -0
  435. package/src/interfaces/desktop/assets/blobs/kiwi.png +0 -0
  436. package/src/interfaces/desktop/assets/blobs/laguna.png +0 -0
  437. package/src/interfaces/desktop/assets/blobs/lila.png +0 -0
  438. package/src/interfaces/desktop/assets/blobs/menta.png +0 -0
  439. package/src/interfaces/desktop/assets/blobs/nimbo.png +0 -0
  440. package/src/interfaces/desktop/assets/blobs/noche.png +0 -0
  441. package/src/interfaces/desktop/assets/blobs/onyx.png +0 -0
  442. package/src/interfaces/desktop/assets/blobs/orbita.png +0 -0
  443. package/src/interfaces/desktop/assets/blobs/ovni.png +0 -0
  444. package/src/interfaces/desktop/assets/blobs/papa.png +0 -0
  445. package/src/interfaces/desktop/assets/blobs/parche.png +0 -0
  446. package/src/interfaces/desktop/assets/blobs/peon.png +0 -0
  447. package/src/interfaces/desktop/assets/blobs/perla.png +0 -0
  448. package/src/interfaces/desktop/assets/blobs/pino.png +0 -0
  449. package/src/interfaces/desktop/assets/blobs/quad.png +0 -0
  450. package/src/interfaces/desktop/assets/blobs/rubi.png +0 -0
  451. package/src/interfaces/desktop/assets/blobs/saturno.png +0 -0
  452. package/src/interfaces/desktop/assets/blobs/trebol.png +0 -0
  453. package/src/interfaces/desktop/assets/blobs/trino.png +0 -0
  454. package/src/interfaces/desktop/assets/blobs/volcan.png +0 -0
  455. package/src/interfaces/desktop/assets/blobs/zafiro.png +0 -0
  456. package/src/interfaces/desktop/assets/notification.mp3 +0 -0
  457. package/src/interfaces/desktop/main.js +473 -29
  458. package/src/interfaces/desktop/mascot-blobs.js +41 -0
  459. package/src/interfaces/desktop/mascot-preload.js +32 -0
  460. package/src/interfaces/desktop/mascot.css +186 -0
  461. package/src/interfaces/desktop/mascot.html +40 -0
  462. package/src/interfaces/desktop/mascot.js +163 -0
  463. package/src/interfaces/desktop/preload.js +10 -0
  464. package/src/interfaces/desktop/renderer.js +308 -48
  465. package/src/interfaces/desktop/style.css +34 -0
  466. package/src/interfaces/mcp-server/index.js +87 -0
  467. package/src/interfaces/tui/_shims/util-locale.ts +0 -2
  468. package/src/interfaces/tui/app.tsx +0 -6
  469. package/src/interfaces/tui/attach.ts +0 -1
  470. package/src/interfaces/tui/context/sdk-apx.tsx +0 -4
  471. package/src/interfaces/tui/plugin/api.tsx +0 -3
  472. package/src/interfaces/tui/plugin/runtime.ts +0 -3
  473. package/src/interfaces/tui/thread.ts +0 -16
  474. package/src/interfaces/web/README.md +22 -14
  475. package/src/interfaces/web/dist/assets/claude-XtpLmGtF.webp +0 -0
  476. package/src/interfaces/web/dist/assets/codex-DExPUgvh.webp +0 -0
  477. package/src/interfaces/web/dist/assets/index-BEoRgIqd.css +32 -0
  478. package/src/interfaces/web/dist/assets/index-BEoRgIqd.css.br +0 -0
  479. package/src/interfaces/web/dist/assets/index-BEoRgIqd.css.gz +0 -0
  480. package/src/interfaces/web/dist/assets/index-C6fXHc1p.js +1074 -0
  481. package/src/interfaces/web/dist/assets/index-C6fXHc1p.js.br +0 -0
  482. package/src/interfaces/web/dist/assets/index-C6fXHc1p.js.gz +0 -0
  483. package/src/interfaces/web/dist/assets/index-C6fXHc1p.js.map +1 -0
  484. package/src/interfaces/web/dist/assets/index-C6fXHc1p.js.map.br +0 -0
  485. package/src/interfaces/web/dist/assets/index-C6fXHc1p.js.map.gz +0 -0
  486. package/src/interfaces/web/dist/favicon/dark/site.webmanifest +12 -6
  487. package/src/interfaces/web/dist/favicon/white/site.webmanifest +12 -6
  488. package/src/interfaces/web/dist/index.html +22 -6
  489. package/src/interfaces/web/dist/index.html.br +0 -0
  490. package/src/interfaces/web/dist/index.html.gz +0 -0
  491. package/src/interfaces/web/dist/manifest.webmanifest +25 -0
  492. package/src/interfaces/web/dist/modules/blobs/amatista.png +0 -0
  493. package/src/interfaces/web/dist/modules/blobs/aqua.png +0 -0
  494. package/src/interfaces/web/dist/modules/blobs/brasa.png +0 -0
  495. package/src/interfaces/web/dist/modules/blobs/campana.png +0 -0
  496. package/src/interfaces/web/dist/modules/blobs/caracol.png +0 -0
  497. package/src/interfaces/web/dist/modules/blobs/carbon.png +0 -0
  498. package/src/interfaces/web/dist/modules/blobs/cobalto.png +0 -0
  499. package/src/interfaces/web/dist/modules/blobs/cometa.png +0 -0
  500. package/src/interfaces/web/dist/modules/blobs/coral.png +0 -0
  501. package/src/interfaces/web/dist/modules/blobs/cubi.png +0 -0
  502. package/src/interfaces/web/dist/modules/blobs/eclipse.png +0 -0
  503. package/src/interfaces/web/dist/modules/blobs/faro.png +0 -0
  504. package/src/interfaces/web/dist/modules/blobs/gajo.png +0 -0
  505. package/src/interfaces/web/dist/modules/blobs/iris.png +0 -0
  506. package/src/interfaces/web/dist/modules/blobs/kiwi.png +0 -0
  507. package/src/interfaces/web/dist/modules/blobs/laguna.png +0 -0
  508. package/src/interfaces/web/dist/modules/blobs/lila.png +0 -0
  509. package/src/interfaces/web/dist/modules/blobs/menta.png +0 -0
  510. package/src/interfaces/web/dist/modules/blobs/nimbo.png +0 -0
  511. package/src/interfaces/web/dist/modules/blobs/noche.png +0 -0
  512. package/src/interfaces/web/dist/modules/blobs/onyx.png +0 -0
  513. package/src/interfaces/web/dist/modules/blobs/orbita.png +0 -0
  514. package/src/interfaces/web/dist/modules/blobs/ovni.png +0 -0
  515. package/src/interfaces/web/dist/modules/blobs/papa.png +0 -0
  516. package/src/interfaces/web/dist/modules/blobs/parche.png +0 -0
  517. package/src/interfaces/web/dist/modules/blobs/peon.png +0 -0
  518. package/src/interfaces/web/dist/modules/blobs/perla.png +0 -0
  519. package/src/interfaces/web/dist/modules/blobs/pino.png +0 -0
  520. package/src/interfaces/web/dist/modules/blobs/quad.png +0 -0
  521. package/src/interfaces/web/dist/modules/blobs/rubi.png +0 -0
  522. package/src/interfaces/web/dist/modules/blobs/saturno.png +0 -0
  523. package/src/interfaces/web/dist/modules/blobs/trebol.png +0 -0
  524. package/src/interfaces/web/dist/modules/blobs/trino.png +0 -0
  525. package/src/interfaces/web/dist/modules/blobs/volcan.png +0 -0
  526. package/src/interfaces/web/dist/modules/blobs/zafiro.png +0 -0
  527. package/src/interfaces/web/dist/sw.js +106 -0
  528. package/src/interfaces/web/dist/sw.js.br +0 -0
  529. package/src/interfaces/web/dist/sw.js.gz +0 -0
  530. package/src/interfaces/web/eslint.config.js +83 -0
  531. package/src/interfaces/web/index.html +20 -4
  532. package/src/interfaces/web/package-lock.json +1651 -1280
  533. package/src/interfaces/web/package.json +9 -10
  534. package/src/interfaces/web/pnpm-lock.yaml +867 -869
  535. package/src/interfaces/web/public/favicon/dark/site.webmanifest +12 -6
  536. package/src/interfaces/web/public/favicon/white/site.webmanifest +12 -6
  537. package/src/interfaces/web/public/manifest.webmanifest +25 -0
  538. package/src/interfaces/web/public/modules/blobs/amatista.png +0 -0
  539. package/src/interfaces/web/public/modules/blobs/aqua.png +0 -0
  540. package/src/interfaces/web/public/modules/blobs/brasa.png +0 -0
  541. package/src/interfaces/web/public/modules/blobs/campana.png +0 -0
  542. package/src/interfaces/web/public/modules/blobs/caracol.png +0 -0
  543. package/src/interfaces/web/public/modules/blobs/carbon.png +0 -0
  544. package/src/interfaces/web/public/modules/blobs/cobalto.png +0 -0
  545. package/src/interfaces/web/public/modules/blobs/cometa.png +0 -0
  546. package/src/interfaces/web/public/modules/blobs/coral.png +0 -0
  547. package/src/interfaces/web/public/modules/blobs/cubi.png +0 -0
  548. package/src/interfaces/web/public/modules/blobs/eclipse.png +0 -0
  549. package/src/interfaces/web/public/modules/blobs/faro.png +0 -0
  550. package/src/interfaces/web/public/modules/blobs/gajo.png +0 -0
  551. package/src/interfaces/web/public/modules/blobs/iris.png +0 -0
  552. package/src/interfaces/web/public/modules/blobs/kiwi.png +0 -0
  553. package/src/interfaces/web/public/modules/blobs/laguna.png +0 -0
  554. package/src/interfaces/web/public/modules/blobs/lila.png +0 -0
  555. package/src/interfaces/web/public/modules/blobs/menta.png +0 -0
  556. package/src/interfaces/web/public/modules/blobs/nimbo.png +0 -0
  557. package/src/interfaces/web/public/modules/blobs/noche.png +0 -0
  558. package/src/interfaces/web/public/modules/blobs/onyx.png +0 -0
  559. package/src/interfaces/web/public/modules/blobs/orbita.png +0 -0
  560. package/src/interfaces/web/public/modules/blobs/ovni.png +0 -0
  561. package/src/interfaces/web/public/modules/blobs/papa.png +0 -0
  562. package/src/interfaces/web/public/modules/blobs/parche.png +0 -0
  563. package/src/interfaces/web/public/modules/blobs/peon.png +0 -0
  564. package/src/interfaces/web/public/modules/blobs/perla.png +0 -0
  565. package/src/interfaces/web/public/modules/blobs/pino.png +0 -0
  566. package/src/interfaces/web/public/modules/blobs/quad.png +0 -0
  567. package/src/interfaces/web/public/modules/blobs/rubi.png +0 -0
  568. package/src/interfaces/web/public/modules/blobs/saturno.png +0 -0
  569. package/src/interfaces/web/public/modules/blobs/trebol.png +0 -0
  570. package/src/interfaces/web/public/modules/blobs/trino.png +0 -0
  571. package/src/interfaces/web/public/modules/blobs/volcan.png +0 -0
  572. package/src/interfaces/web/public/modules/blobs/zafiro.png +0 -0
  573. package/src/interfaces/web/public/sw.js +106 -0
  574. package/src/interfaces/web/src/App.tsx +106 -10
  575. package/src/interfaces/web/src/assets/cli/claude.webp +0 -0
  576. package/src/interfaces/web/src/assets/cli/codex.webp +0 -0
  577. package/src/interfaces/web/src/assets/cli/cursor.svg +1 -0
  578. package/src/interfaces/web/src/assets/cli/opencode.png +0 -0
  579. package/src/interfaces/web/src/components/Combobox.tsx +201 -0
  580. package/src/interfaces/web/src/components/MobileHint.tsx +95 -0
  581. package/src/interfaces/web/src/components/MobileLinkDialog.tsx +156 -0
  582. package/src/interfaces/web/src/components/ModelCombobox.tsx +21 -113
  583. package/src/interfaces/web/src/components/{routines/ReadOnlyBlock.tsx → ReadOnlyBlock.tsx} +13 -4
  584. package/src/interfaces/web/src/components/Roby.tsx +5 -3
  585. package/src/interfaces/web/src/components/RobyBubble.tsx +23 -5
  586. package/src/interfaces/web/src/components/RowMenu.tsx +46 -0
  587. package/src/interfaces/web/src/components/TimezoneSelect.tsx +4 -1
  588. package/src/interfaces/web/src/components/Toast.tsx +50 -14
  589. package/src/interfaces/web/src/components/UiSelect.tsx +12 -5
  590. package/src/interfaces/web/src/components/agents/AgentAvatar.tsx +171 -0
  591. package/src/interfaces/web/src/components/agents/AgentFormFields.tsx +42 -11
  592. package/src/interfaces/web/src/components/agents/AgentModelBadge.tsx +157 -0
  593. package/src/interfaces/web/src/components/agents/AgentModelSelect.tsx +57 -0
  594. package/src/interfaces/web/src/components/agents/AgentSkillsPicker.tsx +115 -0
  595. package/src/interfaces/web/src/components/agents/BlobAvatar.tsx +50 -0
  596. package/src/interfaces/web/src/components/agents/blobPresets.ts +50 -0
  597. package/src/interfaces/web/src/components/agents/modelCatalog.ts +66 -0
  598. package/src/interfaces/web/src/components/chat/ActionGroup.tsx +162 -0
  599. package/src/interfaces/web/src/components/chat/AskAnswersCard.tsx +4 -3
  600. package/src/interfaces/web/src/components/chat/AskQuestionsCard.tsx +1 -1
  601. package/src/interfaces/web/src/components/chat/Attachment.tsx +220 -0
  602. package/src/interfaces/web/src/components/chat/ChatList.tsx +226 -51
  603. package/src/interfaces/web/src/components/chat/ChatRowActivity.tsx +45 -0
  604. package/src/interfaces/web/src/components/chat/Composer.tsx +672 -23
  605. package/src/interfaces/web/src/components/chat/ComposerCommands.tsx +175 -0
  606. package/src/interfaces/web/src/components/chat/ComposerSuggest.tsx +215 -0
  607. package/src/interfaces/web/src/components/chat/ContextBar.tsx +133 -65
  608. package/src/interfaces/web/src/components/chat/InlineAskPanel.tsx +107 -47
  609. package/src/interfaces/web/src/components/chat/MessageBubble.tsx +460 -119
  610. package/src/interfaces/web/src/components/chat/MessageList.tsx +165 -18
  611. package/src/interfaces/web/src/components/chat/ReasoningBlock.tsx +58 -0
  612. package/src/interfaces/web/src/components/chat/SessionPicker.tsx +182 -0
  613. package/src/interfaces/web/src/components/chat/SkillTrace.tsx +183 -0
  614. package/src/interfaces/web/src/components/chat/ToolCall.tsx +11 -11
  615. package/src/interfaces/web/src/components/code/CodeContextTab.tsx +87 -53
  616. package/src/interfaces/web/src/components/code/CodeFileTree.tsx +11 -52
  617. package/src/interfaces/web/src/components/code/CodeFileViewer.tsx +5 -4
  618. package/src/interfaces/web/src/components/code/CodeProjectPicker.tsx +31 -7
  619. package/src/interfaces/web/src/components/code/CodeSessionList.tsx +32 -11
  620. package/src/interfaces/web/src/components/code/CodeSidePanel.tsx +33 -3
  621. package/src/interfaces/web/src/components/code/CodeTerminal.tsx +5 -4
  622. package/src/interfaces/web/src/components/code/NewCodeSessionDialog.tsx +164 -0
  623. package/src/interfaces/web/src/components/commitments/CommitmentDetail.tsx +162 -0
  624. package/src/interfaces/web/src/components/commitments/CommitmentFormDialog.tsx +158 -0
  625. package/src/interfaces/web/src/components/commitments/CommitmentList.tsx +194 -0
  626. package/src/interfaces/web/src/components/commitments/commitmentState.tsx +46 -0
  627. package/src/interfaces/web/src/components/common/BulkActionBar.tsx +60 -0
  628. package/src/interfaces/web/src/components/common/ConfirmDialog.tsx +4 -1
  629. package/src/interfaces/web/src/components/common/SelectCheckbox.tsx +40 -0
  630. package/src/interfaces/web/src/components/common/TabNav.tsx +1 -1
  631. package/src/interfaces/web/src/components/cron/CronPicker.tsx +1 -1
  632. package/src/interfaces/web/src/components/files/FileBrowser.tsx +1 -1
  633. package/src/interfaces/web/src/components/files/FileTree.tsx +6 -4
  634. package/src/interfaces/web/src/components/files/FileViewer.tsx +9 -5
  635. package/src/interfaces/web/src/components/files/MarkdownPreview.tsx +45 -9
  636. package/src/interfaces/web/src/components/images/ImageDefaultsCard.tsx +93 -0
  637. package/src/interfaces/web/src/components/images/ImageProviderList.tsx +142 -0
  638. package/src/interfaces/web/src/components/images/ImageProviderModal.tsx +263 -0
  639. package/src/interfaces/web/src/components/images/ImageTestCard.tsx +142 -0
  640. package/src/interfaces/web/src/components/inbox/ChannelFilter.tsx +178 -0
  641. package/src/interfaces/web/src/components/inbox/InboxList.tsx +77 -81
  642. package/src/interfaces/web/src/components/inbox/InboxRowItem.tsx +140 -0
  643. package/src/interfaces/web/src/components/integrations/ComingSoonPlugin.tsx +2 -2
  644. package/src/interfaces/web/src/components/integrations/PluginConnect.tsx +208 -30
  645. package/src/interfaces/web/src/components/integrations/PluginToolsSection.tsx +1 -1
  646. package/src/interfaces/web/src/components/layout/ProjectAvatar.tsx +39 -24
  647. package/src/interfaces/web/src/components/layout/ProjectSidebar.tsx +253 -58
  648. package/src/interfaces/web/src/components/memory/MemoryBrowser.tsx +94 -47
  649. package/src/interfaces/web/src/components/routines/ExecutionsList.tsx +202 -90
  650. package/src/interfaces/web/src/components/routines/RoutineDetail.tsx +28 -6
  651. package/src/interfaces/web/src/components/routines/RoutineEditor.tsx +16 -5
  652. package/src/interfaces/web/src/components/routines/RoutineList.tsx +49 -9
  653. package/src/interfaces/web/src/components/routines/VarTextarea.tsx +1 -1
  654. package/src/interfaces/web/src/components/routines/runChat.ts +121 -0
  655. package/src/interfaces/web/src/components/sessions/SessionDetail.tsx +148 -0
  656. package/src/interfaces/web/src/components/sessions/SessionTerminal.tsx +98 -0
  657. package/src/interfaces/web/src/components/settings/AccessPanel.tsx +205 -0
  658. package/src/interfaces/web/src/components/settings/DefaultRouterCard.tsx +246 -101
  659. package/src/interfaces/web/src/components/settings/DesktopSettingsPanel.tsx +36 -2
  660. package/src/interfaces/web/src/components/settings/DevicesPanel.tsx +19 -6
  661. package/src/interfaces/web/src/components/settings/EmbedProviderList.tsx +274 -0
  662. package/src/interfaces/web/src/components/settings/EnginesPanel.tsx +26 -6
  663. package/src/interfaces/web/src/components/settings/MemoryPanel.tsx +118 -119
  664. package/src/interfaces/web/src/components/settings/NudgePanel.tsx +4 -3
  665. package/src/interfaces/web/src/components/settings/PairDeviceDialog.tsx +15 -4
  666. package/src/interfaces/web/src/components/settings/PanelPrefs.tsx +374 -0
  667. package/src/interfaces/web/src/components/settings/ProfilePanel.tsx +70 -2
  668. package/src/interfaces/web/src/components/settings/RoutingPanel.tsx +2 -1
  669. package/src/interfaces/web/src/components/settings/SkillsInspectorPanel.tsx +102 -43
  670. package/src/interfaces/web/src/components/settings/SkillsManager.tsx +76 -21
  671. package/src/interfaces/web/src/components/settings/SkillsSettings.tsx +10 -3
  672. package/src/interfaces/web/src/components/settings/SuperAgentPanel.tsx +8 -0
  673. package/src/interfaces/web/src/components/settings/TelegramChannelsPanel.tsx +11 -2
  674. package/src/interfaces/web/src/components/settings/TelegramContactsPanel.tsx +19 -8
  675. package/src/interfaces/web/src/components/settings/TelegramRolesPanel.tsx +12 -2
  676. package/src/interfaces/web/src/components/settings/WebPanel.tsx +22 -31
  677. package/src/interfaces/web/src/components/settings/providers/ProviderCard.tsx +15 -3
  678. package/src/interfaces/web/src/components/settings/providers/ProviderModal.tsx +97 -66
  679. package/src/interfaces/web/src/components/settings/providers/ProviderTestDialog.tsx +150 -0
  680. package/src/interfaces/web/src/components/settings/providers/typeStyles.ts +67 -25
  681. package/src/interfaces/web/src/components/settings/providers/types.ts +3 -0
  682. package/src/interfaces/web/src/components/tasks/TaskBoard.tsx +201 -0
  683. package/src/interfaces/web/src/components/tasks/TaskColumnsDialog.tsx +243 -0
  684. package/src/interfaces/web/src/components/tasks/TaskComments.tsx +167 -0
  685. package/src/interfaces/web/src/components/tasks/TaskDetail.tsx +335 -0
  686. package/src/interfaces/web/src/components/tasks/TaskFormDialog.tsx +406 -0
  687. package/src/interfaces/web/src/components/tasks/TaskList.tsx +258 -0
  688. package/src/interfaces/web/src/components/tasks/TaskSubtasks.tsx +126 -0
  689. package/src/interfaces/web/src/components/tasks/columns.ts +51 -0
  690. package/src/interfaces/web/src/components/tasks/taskStatus.tsx +159 -34
  691. package/src/interfaces/web/src/components/tasks/taskViewPrefs.ts +73 -0
  692. package/src/interfaces/web/src/components/tasks/useTaskColumns.ts +31 -0
  693. package/src/interfaces/web/src/components/ui/chat-input.tsx +136 -12
  694. package/src/interfaces/web/src/components/ui/context-menu.tsx +15 -198
  695. package/src/interfaces/web/src/components/ui/dialog.tsx +3 -2
  696. package/src/interfaces/web/src/components/ui/filter-chips.tsx +4 -0
  697. package/src/interfaces/web/src/components/ui/popover.tsx +14 -49
  698. package/src/interfaces/web/src/components/ui/sheet.tsx +2 -1
  699. package/src/interfaces/web/src/components/ui/spinner.tsx +2 -1
  700. package/src/interfaces/web/src/components/ui.tsx +62 -23
  701. package/src/interfaces/web/src/components/voice/VoiceProviderList.tsx +2 -1
  702. package/src/interfaces/web/src/components/voice/VoiceProviderModal.tsx +66 -8
  703. package/src/interfaces/web/src/components/voice/VoiceQvoxInstallCard.tsx +63 -0
  704. package/src/interfaces/web/src/components/voice/VoiceQvoxStatusCard.tsx +51 -0
  705. package/src/interfaces/web/src/components/voice/VoiceSttCard.tsx +4 -3
  706. package/src/interfaces/web/src/components/voice/VoiceTestCard.tsx +38 -4
  707. package/src/interfaces/web/src/constants/index.ts +1 -0
  708. package/src/interfaces/web/src/hooks/useChannelPrefs.ts +39 -0
  709. package/src/interfaces/web/src/hooks/useChat.ts +1092 -85
  710. package/src/interfaces/web/src/hooks/useChatActivity.ts +24 -0
  711. package/src/interfaces/web/src/hooks/useInbox.ts +26 -4
  712. package/src/interfaces/web/src/hooks/useLiveMessages.ts +16 -0
  713. package/src/interfaces/web/src/hooks/useOllamaModels.ts +79 -0
  714. package/src/interfaces/web/src/hooks/useRecorder.ts +198 -0
  715. package/src/interfaces/web/src/hooks/useTokenBootstrap.ts +23 -6
  716. package/src/interfaces/web/src/i18n/en.ts +832 -175
  717. package/src/interfaces/web/src/i18n/es.ts +841 -188
  718. package/src/interfaces/web/src/lib/api/agents.ts +23 -4
  719. package/src/interfaces/web/src/lib/api/code.ts +17 -0
  720. package/src/interfaces/web/src/lib/api/commitments.ts +7 -1
  721. package/src/interfaces/web/src/lib/api/conversations.ts +38 -11
  722. package/src/interfaces/web/src/lib/api/embeddings.ts +3 -0
  723. package/src/interfaces/web/src/lib/api/engines.ts +14 -0
  724. package/src/interfaces/web/src/lib/api/groups.ts +93 -0
  725. package/src/interfaces/web/src/lib/api/images.ts +193 -0
  726. package/src/interfaces/web/src/lib/api/inbox.ts +29 -5
  727. package/src/interfaces/web/src/lib/api/integrations.ts +9 -0
  728. package/src/interfaces/web/src/lib/api/media.ts +126 -0
  729. package/src/interfaces/web/src/lib/api/net.ts +44 -0
  730. package/src/interfaces/web/src/lib/api/profiles.ts +12 -0
  731. package/src/interfaces/web/src/lib/api/projects.ts +9 -1
  732. package/src/interfaces/web/src/lib/api/routines.ts +9 -1
  733. package/src/interfaces/web/src/lib/api/sessions.ts +18 -0
  734. package/src/interfaces/web/src/lib/api/skills.ts +8 -0
  735. package/src/interfaces/web/src/lib/api/super_agent.ts +3 -0
  736. package/src/interfaces/web/src/lib/api/tasks.ts +46 -6
  737. package/src/interfaces/web/src/lib/api/tools.ts +2 -0
  738. package/src/interfaces/web/src/lib/api/transcribe.ts +31 -0
  739. package/src/interfaces/web/src/lib/api/turns.ts +20 -0
  740. package/src/interfaces/web/src/lib/api/voice.ts +72 -2
  741. package/src/interfaces/web/src/lib/api.ts +3 -0
  742. package/src/interfaces/web/src/lib/channels.ts +214 -0
  743. package/src/interfaces/web/src/lib/chat-activity.ts +175 -0
  744. package/src/interfaces/web/src/lib/chat-prefs.ts +48 -0
  745. package/src/interfaces/web/src/lib/code-context.ts +0 -2
  746. package/src/interfaces/web/src/lib/http.ts +51 -17
  747. package/src/interfaces/web/src/lib/inbox-selection.ts +29 -0
  748. package/src/interfaces/web/src/lib/live.ts +252 -0
  749. package/src/interfaces/web/src/lib/net.ts +211 -0
  750. package/src/interfaces/web/src/lib/notify.ts +331 -0
  751. package/src/interfaces/web/src/lib/projectNav.ts +40 -0
  752. package/src/interfaces/web/src/lib/pwa.ts +115 -0
  753. package/src/interfaces/web/src/lib/qvox.ts +24 -0
  754. package/src/interfaces/web/src/lib/slug.ts +3 -0
  755. package/src/interfaces/web/src/lib/tone.ts +150 -0
  756. package/src/interfaces/web/src/main.tsx +15 -4
  757. package/src/interfaces/web/src/screens/ApxAdminScreen.tsx +33 -11
  758. package/src/interfaces/web/src/screens/InboxScreen.tsx +126 -71
  759. package/src/interfaces/web/src/screens/ProjectScreen.tsx +8 -4
  760. package/src/interfaces/web/src/screens/SettingsScreen.tsx +7 -4
  761. package/src/interfaces/web/src/screens/base/AgentDefaultsTab.tsx +30 -9
  762. package/src/interfaces/web/src/screens/base/CommitmentsTab.tsx +150 -168
  763. package/src/interfaces/web/src/screens/base/LogsTab.tsx +8 -7
  764. package/src/interfaces/web/src/screens/base/SessionsTab.tsx +99 -37
  765. package/src/interfaces/web/src/screens/base/WorkspacesTab.tsx +1 -1
  766. package/src/interfaces/web/src/screens/mobile/MobileChat.tsx +85 -0
  767. package/src/interfaces/web/src/screens/mobile/MobileChatList.tsx +244 -0
  768. package/src/interfaces/web/src/screens/mobile/MobileCommitments.tsx +350 -0
  769. package/src/interfaces/web/src/screens/mobile/MobileScreen.tsx +138 -0
  770. package/src/interfaces/web/src/screens/mobile/MobileTabBar.tsx +105 -0
  771. package/src/interfaces/web/src/screens/mobile/MobileTasks.tsx +407 -0
  772. package/src/interfaces/web/src/screens/mobile/NewChatSheet.tsx +313 -0
  773. package/src/interfaces/web/src/screens/mobile/mobileList.tsx +194 -0
  774. package/src/interfaces/web/src/screens/mobile/routes.ts +239 -0
  775. package/src/interfaces/web/src/screens/modules/CodeScreen.tsx +135 -64
  776. package/src/interfaces/web/src/screens/modules/DeckScreen.tsx +0 -1
  777. package/src/interfaces/web/src/screens/modules/ImagesScreen.tsx +172 -0
  778. package/src/interfaces/web/src/screens/modules/VoiceScreen.tsx +36 -4
  779. package/src/interfaces/web/src/screens/project/AgentBrainGraph.tsx +117 -30
  780. package/src/interfaces/web/src/screens/project/AgentDetailScreen.tsx +537 -92
  781. package/src/interfaces/web/src/screens/project/AgentsTab.tsx +344 -93
  782. package/src/interfaces/web/src/screens/project/ArtifactsTab.tsx +1 -1
  783. package/src/interfaces/web/src/screens/project/ChatTab.tsx +1160 -94
  784. package/src/interfaces/web/src/screens/project/IntegrationsTab.tsx +3 -2
  785. package/src/interfaces/web/src/screens/project/McpsTab.tsx +62 -14
  786. package/src/interfaces/web/src/screens/project/Overview.tsx +36 -15
  787. package/src/interfaces/web/src/screens/project/RoutinesTab.tsx +93 -8
  788. package/src/interfaces/web/src/screens/project/SkillsTab.tsx +4 -1
  789. package/src/interfaces/web/src/screens/project/StructureTab.tsx +5 -4
  790. package/src/interfaces/web/src/screens/project/TasksTab.tsx +351 -129
  791. package/src/interfaces/web/src/screens/project/VarsTab.tsx +17 -5
  792. package/src/interfaces/web/src/styles.css +106 -31
  793. package/src/interfaces/web/src/types/daemon.ts +246 -2
  794. package/src/interfaces/web/src/vite-env.d.ts +20 -0
  795. package/src/interfaces/tui/plugin/command-shim.ts +0 -109
  796. package/src/interfaces/web/components.json +0 -25
  797. package/src/interfaces/web/dist/assets/index-CvEoGtTf.js +0 -849
  798. package/src/interfaces/web/dist/assets/index-CvEoGtTf.js.map +0 -1
  799. package/src/interfaces/web/dist/assets/index-DzBBXFaO.css +0 -1
  800. package/src/interfaces/web/src/components/tasks/TaskDetailPanel.tsx +0 -142
  801. package/src/interfaces/web/src/components/ui/accordion.tsx +0 -72
  802. package/src/interfaces/web/src/components/ui/alert-dialog.tsx +0 -187
  803. package/src/interfaces/web/src/components/ui/alert.tsx +0 -76
  804. package/src/interfaces/web/src/components/ui/aspect-ratio.tsx +0 -22
  805. package/src/interfaces/web/src/components/ui/avatar.tsx +0 -107
  806. package/src/interfaces/web/src/components/ui/breadcrumb.tsx +0 -125
  807. package/src/interfaces/web/src/components/ui/button-group.tsx +0 -87
  808. package/src/interfaces/web/src/components/ui/calendar.tsx +0 -221
  809. package/src/interfaces/web/src/components/ui/card.tsx +0 -103
  810. package/src/interfaces/web/src/components/ui/carousel.tsx +0 -242
  811. package/src/interfaces/web/src/components/ui/chart.tsx +0 -371
  812. package/src/interfaces/web/src/components/ui/checkbox.tsx +0 -29
  813. package/src/interfaces/web/src/components/ui/collapsible.tsx +0 -19
  814. package/src/interfaces/web/src/components/ui/combobox.tsx +0 -295
  815. package/src/interfaces/web/src/components/ui/command.tsx +0 -196
  816. package/src/interfaces/web/src/components/ui/direction.tsx +0 -4
  817. package/src/interfaces/web/src/components/ui/drawer.tsx +0 -134
  818. package/src/interfaces/web/src/components/ui/empty.tsx +0 -104
  819. package/src/interfaces/web/src/components/ui/field.tsx +0 -236
  820. package/src/interfaces/web/src/components/ui/hover-card.tsx +0 -51
  821. package/src/interfaces/web/src/components/ui/input-otp.tsx +0 -85
  822. package/src/interfaces/web/src/components/ui/item.tsx +0 -201
  823. package/src/interfaces/web/src/components/ui/menubar.tsx +0 -280
  824. package/src/interfaces/web/src/components/ui/native-select.tsx +0 -61
  825. package/src/interfaces/web/src/components/ui/navigation-menu.tsx +0 -168
  826. package/src/interfaces/web/src/components/ui/pagination.tsx +0 -130
  827. package/src/interfaces/web/src/components/ui/progress.tsx +0 -83
  828. package/src/interfaces/web/src/components/ui/radio-group.tsx +0 -36
  829. package/src/interfaces/web/src/components/ui/resizable.tsx +0 -50
  830. package/src/interfaces/web/src/components/ui/scroll-area.tsx +0 -53
  831. package/src/interfaces/web/src/components/ui/sidebar.tsx +0 -726
  832. package/src/interfaces/web/src/components/ui/slider.tsx +0 -52
  833. package/src/interfaces/web/src/components/ui/sonner.tsx +0 -49
  834. package/src/interfaces/web/src/components/ui/table.tsx +0 -116
  835. package/src/interfaces/web/src/components/ui/toggle-group.tsx +0 -87
  836. package/src/interfaces/web/src/components/ui/toggle.tsx +0 -45
  837. package/src/interfaces/web/src/hooks/use-mobile.ts +0 -19
  838. package/src/interfaces/web/src/screens/base/GlobalTasksTab.tsx +0 -161
@@ -9,7 +9,7 @@
9
9
  // Or via: apx desktop start
10
10
 
11
11
  "use strict";
12
- const { app, BrowserWindow, Tray, globalShortcut, ipcMain, nativeImage, screen, Menu } = require("electron");
12
+ const { app, BrowserWindow, Tray, globalShortcut, ipcMain, nativeImage, screen, Menu, shell } = require("electron");
13
13
  const path = require("path");
14
14
  const os = require("os");
15
15
  const fs = require("fs");
@@ -124,6 +124,54 @@ function getAgentName() {
124
124
  return "Superagente";
125
125
  }
126
126
 
127
+ // ── Mascot (blob pet) config ────────────────────────────────────────────────
128
+ // Which blob the pet wears: the shared super-agent avatar, then the legacy
129
+ // desktop-only override, then the default. The web picker writes the shared key.
130
+ function getMascotBlob() {
131
+ const cfg = readApxConfig();
132
+ const key = cfg?.super_agent?.icon || cfg?.desktop?.blob;
133
+ return (typeof key === "string" && key.trim()) ? key.trim() : "noche";
134
+ }
135
+
136
+ // The pet is on by default — the user asked for it. Disable with
137
+ // "desktop": { "mascot": false }
138
+ function getMascotEnabled() {
139
+ const cfg = readApxConfig();
140
+ return cfg?.desktop?.mascot !== false;
141
+ }
142
+
143
+ // Message sounds are on by default. The checkbox in the native context menus
144
+ // persists this setting independently from the mascot visibility toggle.
145
+ function getMascotSoundEnabled() {
146
+ const cfg = readApxConfig();
147
+ return cfg?.desktop?.mascot_sound !== false;
148
+ }
149
+
150
+ // Saved pet position ({x,y} in screen coords), or null for the default corner.
151
+ function getMascotPos() {
152
+ const cfg = readApxConfig();
153
+ const p = cfg?.desktop?.mascot_pos;
154
+ if (p && typeof p.x === "number" && typeof p.y === "number") return p;
155
+ return null;
156
+ }
157
+
158
+ // Persist a partial patch into config.json's `desktop` block, preserving every
159
+ // other field. Best-effort — a write failure just means the pet forgets where
160
+ // it was left, which is harmless.
161
+ function patchDesktopConfig(patch) {
162
+ try {
163
+ const cfg = readApxConfig();
164
+ cfg.desktop = { ...(cfg.desktop || {}), ...patch };
165
+ fs.writeFileSync(CONFIG_PATH, JSON.stringify(cfg, null, 2) + "\n", "utf8");
166
+ } catch (e) {
167
+ console.warn("desktop: could not persist mascot config —", e.message);
168
+ }
169
+ }
170
+
171
+ function toggleMascotSound() {
172
+ patchDesktopConfig({ mascot_sound: !getMascotSoundEnabled() });
173
+ }
174
+
127
175
  function getWindowOrigin(_height) {
128
176
  const display = screen.getPrimaryDisplay();
129
177
  const { workArea } = display;
@@ -139,6 +187,7 @@ function getWindowOrigin(_height) {
139
187
  // ---------------------------------------------------------------------------
140
188
 
141
189
  let mainWindow = null;
190
+ let mascotWindow = null; // the draggable blob pet (separate always-on-top window)
142
191
  let tray = null;
143
192
  let wsConn = null; // WebSocket to daemon
144
193
  let isRecording = false;
@@ -169,9 +218,12 @@ app.whenReady().then(() => {
169
218
  catch (e) { console.error("desktop: createTray failed:", e.message); }
170
219
  try { createWindow(); console.log("desktop: window created"); }
171
220
  catch (e) { console.error("desktop: createWindow failed:", e.message); }
221
+ try { if (getMascotEnabled()) { createMascotWindow(); console.log("desktop: mascot created"); } }
222
+ catch (e) { console.error("desktop: createMascotWindow failed:", e.message); }
172
223
  try { registerShortcut(); }
173
224
  catch (e) { console.error("desktop: registerShortcut failed:", e.message); }
174
225
  connectDaemon();
226
+ connectEventsFeed();
175
227
  });
176
228
 
177
229
  process.on("uncaughtException", (e) => {
@@ -213,13 +265,28 @@ function createTray() {
213
265
  tray = new Tray(icon);
214
266
 
215
267
  // No extra text label on macOS — the icon is the brand mark.
216
- tray.setToolTip("APX Desktop — click to toggle, right-click for menu");
268
+ tray.setToolTip("APX Desktop — click para abrir, click derecho para el menú");
217
269
 
218
- const contextMenu = Menu.buildFromTemplate([
219
- { label: "Show / Hide", click: toggleWindow },
220
- { label: "Start Recording", click: () => { showOverlay(); startRecording(); } },
270
+ // Built fresh on each right-click so the "Blob mascota" checkbox reflects the
271
+ // pet's live on/off state.
272
+ const buildMenu = () => Menu.buildFromTemplate([
273
+ { label: "Mostrar / ocultar", click: toggleWindow },
274
+ { label: "Grabar", click: () => { showOverlay(); startRecording(); } },
221
275
  { type: "separator" },
222
- { label: "Quit APX Desktop", click: () => app.exit(0) },
276
+ {
277
+ label: "Blob mascota",
278
+ type: "checkbox",
279
+ checked: !!mascotWindow,
280
+ click: toggleMascot,
281
+ },
282
+ {
283
+ label: "Sonido de mensajes",
284
+ type: "checkbox",
285
+ checked: getMascotSoundEnabled(),
286
+ click: toggleMascotSound,
287
+ },
288
+ { type: "separator" },
289
+ { label: "Salir de APX Desktop", click: () => app.exit(0) },
223
290
  ]);
224
291
 
225
292
  // IMPORTANT on macOS: do NOT call tray.setContextMenu(contextMenu).
@@ -229,7 +296,7 @@ function createTray() {
229
296
  // left-click → toggle the floating window
230
297
  // right-click → pop up the context menu
231
298
  tray.on("click", () => toggleWindow());
232
- tray.on("right-click", () => tray.popUpContextMenu(contextMenu));
299
+ tray.on("right-click", () => tray.popUpContextMenu(buildMenu()));
233
300
  }
234
301
 
235
302
  function updateTrayRecording(rec) {
@@ -337,6 +404,92 @@ function reloadDesktopWindow() {
337
404
  }
338
405
  }
339
406
 
407
+ // ---------------------------------------------------------------------------
408
+ // Mascot (blob pet) window
409
+ // ---------------------------------------------------------------------------
410
+ //
411
+ // A second, tiny, transparent, always-on-top window that hosts just the blob
412
+ // avatar. It is draggable anywhere on screen, click-through over its
413
+ // transparent pixels (only the blob + bubble opt back into the mouse), and
414
+ // floats notification bubbles relayed from the daemon. Clicking it toggles the
415
+ // voice HUD. Kept fully separate from the voice window so neither disturbs the
416
+ // other.
417
+
418
+ const MASCOT_W = 240;
419
+ const MASCOT_H = 210;
420
+ const MASCOT_MARGIN = 16;
421
+
422
+ function getMascotOrigin() {
423
+ const saved = getMascotPos();
424
+ const { workArea } = screen.getPrimaryDisplay();
425
+ if (saved) {
426
+ // Clamp a stale saved position back onto the visible work area.
427
+ const x = Math.min(Math.max(saved.x, workArea.x), workArea.x + workArea.width - MASCOT_W);
428
+ const y = Math.min(Math.max(saved.y, workArea.y), workArea.y + workArea.height - MASCOT_H);
429
+ return { x: Math.round(x), y: Math.round(y) };
430
+ }
431
+ // Default: bottom-right corner, above the dock/taskbar.
432
+ return {
433
+ x: workArea.x + workArea.width - MASCOT_W - MASCOT_MARGIN,
434
+ y: workArea.y + workArea.height - MASCOT_H - MASCOT_MARGIN,
435
+ };
436
+ }
437
+
438
+ function createMascotWindow() {
439
+ if (mascotWindow) return;
440
+ const origin = getMascotOrigin();
441
+ mascotWindow = new BrowserWindow({
442
+ width: MASCOT_W,
443
+ height: MASCOT_H,
444
+ x: origin.x,
445
+ y: origin.y,
446
+ frame: false,
447
+ transparent: true,
448
+ alwaysOnTop: true,
449
+ skipTaskbar: true,
450
+ resizable: false,
451
+ hasShadow: false,
452
+ focusable: false, // a pet never steals keyboard focus
453
+ fullscreenable: false,
454
+ show: false,
455
+ webPreferences: {
456
+ preload: path.join(__dirname, "mascot-preload.js"),
457
+ contextIsolation: true,
458
+ nodeIntegration: false,
459
+ autoplayPolicy: "no-user-gesture-required",
460
+ },
461
+ });
462
+
463
+ // Follow the user across spaces / full-screen apps, and float above them.
464
+ try {
465
+ mascotWindow.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true });
466
+ mascotWindow.setAlwaysOnTop(true, "screen-saver");
467
+ } catch {}
468
+
469
+ // Start click-through; the renderer re-enables the mouse only over the blob.
470
+ mascotWindow.setIgnoreMouseEvents(true, { forward: true });
471
+
472
+ mascotWindow.loadFile(path.join(__dirname, "mascot.html"));
473
+ mascotWindow.once("ready-to-show", () => mascotWindow.showInactive());
474
+ mascotWindow.on("closed", () => { mascotWindow = null; });
475
+ }
476
+
477
+ function destroyMascotWindow() {
478
+ if (!mascotWindow) return;
479
+ try { mascotWindow.close(); } catch {}
480
+ mascotWindow = null;
481
+ }
482
+
483
+ function toggleMascot() {
484
+ if (mascotWindow) {
485
+ destroyMascotWindow();
486
+ patchDesktopConfig({ mascot: false });
487
+ } else {
488
+ patchDesktopConfig({ mascot: true });
489
+ createMascotWindow();
490
+ }
491
+ }
492
+
340
493
  // ---------------------------------------------------------------------------
341
494
  // Global shortcut: Cmd/Ctrl+Shift+Space toggles recording
342
495
  // ---------------------------------------------------------------------------
@@ -423,9 +576,8 @@ ipcMain.handle("cancel", async () => {
423
576
  stopRecording();
424
577
  });
425
578
 
426
- // Renderer requests close/hide (legacy "close-overlay" still accepted)
579
+ // Renderer requests close/hide
427
580
  ipcMain.handle("close-desktop", async () => { hideOverlay(); });
428
- ipcMain.handle("close-overlay", async () => { hideOverlay(); });
429
581
 
430
582
  // Renderer queries the configured shortcut for display
431
583
  ipcMain.handle("get-shortcut", () => getShortcut());
@@ -434,6 +586,77 @@ ipcMain.handle("get-position", () => getPosition());
434
586
  ipcMain.handle("get-agent-name", () => getAgentName());
435
587
  ipcMain.handle("get-voice-timing", () => getVoiceTiming());
436
588
 
589
+ // ── Mascot (blob pet) IPC ───────────────────────────────────────────────────
590
+ ipcMain.handle("mascot-get-config", () => ({
591
+ blob: getMascotBlob(),
592
+ name: getAgentName(),
593
+ theme: getTheme(),
594
+ sound: getMascotSoundEnabled(),
595
+ }));
596
+
597
+ ipcMain.handle("mascot-get-bounds", () => {
598
+ if (!mascotWindow) return { x: 0, y: 0, width: MASCOT_W, height: MASCOT_H };
599
+ return mascotWindow.getBounds();
600
+ });
601
+
602
+ ipcMain.on("mascot-set-pos", (_e, { x, y }) => {
603
+ if (!mascotWindow) return;
604
+ if (typeof x !== "number" || typeof y !== "number") return;
605
+ mascotWindow.setPosition(Math.round(x), Math.round(y));
606
+ });
607
+
608
+ ipcMain.on("mascot-save-pos", () => {
609
+ if (!mascotWindow) return;
610
+ const [x, y] = mascotWindow.getPosition();
611
+ patchDesktopConfig({ mascot_pos: { x, y } });
612
+ });
613
+
614
+ // A clean click on the blob toggles the voice HUD.
615
+ ipcMain.handle("mascot-poke", () => { toggleWindow(); });
616
+
617
+ // Right-click on the blob → a native context menu at the cursor. Mirrors the
618
+ // tray menu, plus a shortcut to open the full chat in the browser.
619
+ ipcMain.handle("mascot-menu", () => {
620
+ const menu = Menu.buildFromTemplate([
621
+ { label: "Abrir chat en el navegador", click: openWebChat },
622
+ { type: "separator" },
623
+ { label: "Mostrar / ocultar voz", click: toggleWindow },
624
+ { label: "Grabar", click: () => { showOverlay(); startRecording(); } },
625
+ { label: "Probar notificación", click: testMascotNotify },
626
+ { type: "separator" },
627
+ { label: "Blob mascota", type: "checkbox", checked: !!mascotWindow, click: toggleMascot },
628
+ { label: "Sonido de mensajes", type: "checkbox", checked: getMascotSoundEnabled(), click: toggleMascotSound },
629
+ { type: "separator" },
630
+ { label: "Salir", click: () => app.exit(0) },
631
+ ]);
632
+ menu.popup({ window: mascotWindow || undefined });
633
+ });
634
+
635
+ // Fire a sample bubble on the pet — lets you preview notifications without
636
+ // sending a real message through a channel.
637
+ function testMascotNotify() {
638
+ if (!mascotWindow) return;
639
+ mascotWindow.webContents.send("mascot-notify", {
640
+ text: "Nuevo mensaje en Telegram",
641
+ sound: getMascotSoundEnabled(),
642
+ });
643
+ }
644
+
645
+ // Open the APX web chat in the user's default browser. The daemon serves the
646
+ // web UI at its own host:port.
647
+ function openWebChat() {
648
+ const url = `http://${DAEMON_HOST}:${DAEMON_PORT}/`;
649
+ shell.openExternal(url).catch((e) => console.warn("desktop: openWebChat failed —", e.message));
650
+ }
651
+
652
+ // Click-through toggling — ignore the mouse over transparent pixels, capture it
653
+ // over the blob/bubble. `forward:true` keeps move events flowing so the
654
+ // renderer can tell when the pointer re-enters an interactive region.
655
+ ipcMain.on("mascot-set-ignore", (_e, { ignore }) => {
656
+ if (!mascotWindow) return;
657
+ mascotWindow.setIgnoreMouseEvents(!!ignore, { forward: true });
658
+ });
659
+
437
660
  // Renderer asks main to grow/shrink the window to fit its content.
438
661
  // Clamped to [WIN_H_MIN, getMaxWindowHeight()]; same anchor (top edge stays put).
439
662
  ipcMain.on("resize-window", (_e, { height }) => {
@@ -447,29 +670,116 @@ ipcMain.on("resize-window", (_e, { height }) => {
447
670
  // Renderer asks for TTS playback of the agent reply. We synthesize via the
448
671
  // daemon and pipe the audio path back as a daemon-event the renderer already
449
672
  // knows how to consume (tts-ready { url, duration } / tts-failed).
673
+ // Speech is generated a sentence at a time so the first one can start playing
674
+ // while the rest is still being made. The engine runs at roughly 0.85x real
675
+ // time, which means every sentence finishes generating before the one ahead of
676
+ // it finishes playing — so the reply comes out continuous, but Roby starts
677
+ // talking after the first sentence instead of after the whole answer. Measured
678
+ // on a two-sentence reply: first audio at 2.0s instead of 4.8s, and the gap
679
+ // grows with the length of the answer.
680
+ //
681
+ // The limit mirrors the engine's own chunking. Past ~80 characters the model
682
+ // stops finding its end token and the audio degrades, so there is nothing to
683
+ // gain by sending it more in one go.
684
+ function splitForSpeech(text, { min = 12, limit = 80 } = {}) {
685
+ const out = [];
686
+ let cur = "";
687
+ const flush = () => { if (cur) { out.push(cur); cur = ""; } };
688
+ const add = (piece) => {
689
+ if (!piece) return;
690
+ if (cur && cur.length + 1 + piece.length > limit) flush();
691
+ cur = cur ? `${cur} ${piece}` : piece;
692
+ // Cut as soon as there is enough to say. Packing sentences up to the limit
693
+ // would undo the point of this: two sentences that fit in one chunk get
694
+ // generated together, and the listener waits for both before hearing
695
+ // either. `min` only exists so a two-word sentence doesn't become a
696
+ // generation of its own, and it is deliberately small: a short greeting
697
+ // degrades the whole chunk it is folded into. "¡Hola Manu!" alone is
698
+ // bounded to about a second of possible damage, but merged ahead of a full
699
+ // sentence it took the pair from 13 chars/s down to 8.
700
+ if (cur.length >= min) flush();
701
+ };
702
+ for (const sentence of String(text).trim().split(/(?<=[.!?…])\s+/)) {
703
+ if (sentence.length <= limit) { add(sentence); continue; }
704
+ // A sentence too long on its own: break it at clauses, then words.
705
+ for (const clause of sentence.split(/(?<=[,;:—–])\s+/)) {
706
+ if (clause.length <= limit) { add(clause); continue; }
707
+ for (const word of clause.split(" ")) add(word);
708
+ }
709
+ }
710
+ flush();
711
+ return out.length ? out : [String(text)];
712
+ }
713
+
714
+ // Speech generated ahead of the request for it, keyed by the exact chunk text.
715
+ // The renderer kicks this the moment the first sentence has streamed in, so the
716
+ // voice engine works during the model's remaining tokens instead of after them
717
+ // — the single longest stretch of dead time in a voice turn. A key that never
718
+ // gets claimed just means one small wasted synthesis, never wrong audio: only
719
+ // an exact text match is ever served from here.
720
+ const ttsAhead = new Map(); // chunk text -> Promise<{ok, audio_path, ...}>
721
+
722
+ ipcMain.handle("prewarm-tts", async (_e, { text }) => {
723
+ const first = splitForSpeech(text || "")[0];
724
+ // splitForSpeech packs sentences shorter than its `min` together with the
725
+ // next one, so a short opener would be pre-made as the wrong chunk. The
726
+ // renderer already filters those out; this is the backstop.
727
+ if (!first || first !== (text || "").trim() || ttsAhead.has(first)) return;
728
+ if (ttsAhead.size > 4) ttsAhead.clear(); // a turn never needs more than one
729
+ const t0 = Date.now();
730
+ ttsAhead.set(first, daemonTtsSay(first)
731
+ .then((r) => {
732
+ console.log(`desktop: speech-ahead ready in ${Date.now() - t0}ms — "${first.slice(0, 48)}"`);
733
+ return r;
734
+ })
735
+ .catch(() => ({ ok: false })));
736
+ });
737
+
450
738
  ipcMain.handle("request-tts", async (_e, { text, seg }) => {
739
+ const send = (msg) => mainWindow?.webContents.send("daemon-event", msg);
451
740
  if (!text || !text.trim()) {
452
- mainWindow?.webContents.send("daemon-event", { type: "tts-failed", seg });
741
+ send({ type: "tts-failed", seg });
453
742
  return;
454
743
  }
744
+ const chunks = splitForSpeech(text);
745
+ let delivered = 0;
455
746
  try {
456
- const result = await daemonTtsSay(text);
457
- if (result?.ok && result.audio_path) {
458
- // Expose the local file via file:// — preload's contextIsolation lets
459
- // the renderer's <audio> tag fetch it directly. `seg` ties this audio to
460
- // the bubble that asked for it.
461
- const url = "file://" + result.audio_path;
462
- mainWindow?.webContents.send("daemon-event", {
463
- type: "tts-ready",
464
- seg,
465
- url,
466
- duration: result.duration_s || 0,
467
- });
468
- } else {
469
- mainWindow?.webContents.send("daemon-event", { type: "tts-failed", seg, error: result?.error || "no audio" });
747
+ for (const chunk of chunks) {
748
+ const ahead = ttsAhead.get(chunk);
749
+ if (ahead) ttsAhead.delete(chunk);
750
+ if (delivered === 0) {
751
+ console.log(`desktop: first chunk ${ahead ? "claimed from speech-ahead" : "synthesized on demand"}`);
752
+ }
753
+ const result = ahead ? await ahead : await daemonTtsSay(chunk);
754
+ if (result?.ok && result.audio_path) {
755
+ // Expose the local file via file:// — preload's contextIsolation lets
756
+ // the renderer's <audio> tag fetch it directly. `seg` ties this audio
757
+ // to the bubble that asked for it.
758
+ send({
759
+ type: "tts-part",
760
+ seg,
761
+ url: "file://" + result.audio_path,
762
+ duration: result.duration_s || 0,
763
+ });
764
+ delivered++;
765
+ } else if (!delivered) {
766
+ // Nothing has played yet and the engine is refusing: stop asking. A
767
+ // whole reply of failures would otherwise cost one full timeout each.
768
+ send({ type: "tts-failed", seg, error: result?.error || "no audio" });
769
+ return;
770
+ }
771
+ // A later chunk failing is survivable — the bubble keeps what it has.
470
772
  }
773
+ // Anything still sitting here was pre-made for a sentence this reply never
774
+ // asked for (the model revised it, or a tag/emoji changed the chunk).
775
+ ttsAhead.clear();
776
+ // Tells the renderer no more audio is coming, so a player waiting on the
777
+ // next sentence knows it has reached the end instead of stalling.
778
+ send({ type: "tts-end", seg, parts: delivered });
779
+ if (!delivered) send({ type: "tts-failed", seg, error: "no audio" });
471
780
  } catch (e) {
472
- mainWindow?.webContents.send("daemon-event", { type: "tts-failed", seg, error: e.message });
781
+ if (delivered) send({ type: "tts-end", seg, parts: delivered });
782
+ else send({ type: "tts-failed", seg, error: e.message });
473
783
  }
474
784
  });
475
785
 
@@ -526,6 +836,30 @@ ipcMain.handle("warmup-stt", async () => {
526
836
  });
527
837
  });
528
838
 
839
+ // Same idea as warmup-stt, for the other half of the round trip. Fired when
840
+ // the mic opens: the user then spends a few seconds speaking, and the voice
841
+ // engine spends them getting its weights back into RAM instead of making the
842
+ // reply wait afterwards.
843
+ ipcMain.handle("warmup-tts", async () => {
844
+ return new Promise((resolve) => {
845
+ const token = readToken();
846
+ const req = http.request({
847
+ hostname: DAEMON_HOST,
848
+ port: DAEMON_PORT,
849
+ path: "/api/tts/warmup",
850
+ method: "GET",
851
+ headers: { ...(token ? { "Authorization": `Bearer ${token}` } : {}) },
852
+ }, (res) => {
853
+ let data = "";
854
+ res.on("data", (c) => data += c);
855
+ res.on("end", () => { try { resolve(JSON.parse(data)); } catch { resolve({ ok: false }); } });
856
+ });
857
+ req.on("error", () => resolve({ ok: false }));
858
+ req.setTimeout(120000, () => { req.destroy(); resolve({ ok: false }); });
859
+ req.end();
860
+ });
861
+ });
862
+
529
863
  // Renderer requests recording toggle (ESC cancels, shortcut toggles)
530
864
  ipcMain.handle("toggle-recording", async () => {
531
865
  if (isRecording) stopRecording(); else startRecording();
@@ -644,6 +978,104 @@ function connectDaemon() {
644
978
  connect();
645
979
  }
646
980
 
981
+ // ---------------------------------------------------------------------------
982
+ // Cross-channel event feed → mascot notifications
983
+ // ---------------------------------------------------------------------------
984
+ //
985
+ // A SECOND socket, to /api/events/ws (distinct from the desktop conversation
986
+ // socket above). It carries a signal-only "the channel X moved" feed. The
987
+ // daemon already decided which bursts are news (`notifications: string[]`):
988
+ // an agent's launched final on Telegram / group / A2A, plus delivery
989
+ // headlines. The owner's own send is NOT news — it used to bubble here
990
+ // because the filter watched `direction: "in"`. Only meaningful while the
991
+ // pet is on.
992
+
993
+ function connectEventsFeed() {
994
+ let WS;
995
+ try { WS = require("ws"); } catch { return; } // already warned in connectDaemon
996
+
997
+ const url = `ws://${DAEMON_HOST}:${DAEMON_PORT}/api/events/ws`;
998
+ let conn = null;
999
+ let reconnectDelay = 1000;
1000
+
1001
+ function scheduleReconnect() {
1002
+ const delay = reconnectDelay;
1003
+ reconnectDelay = Math.min(reconnectDelay * 2, 30000);
1004
+ setTimeout(connect, delay);
1005
+ }
1006
+
1007
+ function pushBubble(text) {
1008
+ if (!text || !mascotWindow) return;
1009
+ mascotWindow.webContents.send("mascot-notify", { text, sound: getMascotSoundEnabled() });
1010
+ }
1011
+
1012
+ function handleFrame(msg) {
1013
+ const avatar = msg?.settings?.super_agent?.icon;
1014
+ if ((msg?.type === "hello" || msg?.type === "settings") && typeof avatar === "string") {
1015
+ mascotWindow?.webContents.send("mascot-avatar", avatar);
1016
+ }
1017
+ if (!msg || msg.type !== "messages") return;
1018
+ if (!mascotWindow) return; // pet off → nothing to notify
1019
+
1020
+ // The daemon computes the copy. An empty array means "this burst is not
1021
+ // news" (the owner sending) and must not fall through to a local guess.
1022
+ if (Array.isArray(msg.notifications)) {
1023
+ for (const text of msg.notifications) pushBubble(text);
1024
+ return;
1025
+ }
1026
+
1027
+ // Older daemon without the field: still skip the owner's send, only
1028
+ // bubble an agent's launched final on Telegram / group / A2A plus the
1029
+ // delivery headlines the previous local filter already knew about.
1030
+ const events = Array.isArray(msg.events) ? msg.events : [];
1031
+ for (const ev of events) {
1032
+ if (ev?.via === "mobility_delivery" && ev.notify) pushBubble(ev.notify);
1033
+ }
1034
+ const byAgent = new Map();
1035
+ for (const ev of events) {
1036
+ if (!ev || ev.via !== "routine_delivery" || ev.channel !== "web") continue;
1037
+ if (!ev.agent_slug || ev.agent_slug === "super_agent") continue;
1038
+ byAgent.set(ev.agent_slug, ev.notify || byAgent.get(ev.agent_slug) || "");
1039
+ }
1040
+ for (const [agent, notify] of byAgent) {
1041
+ pushBubble(notify ? `${agent}: ${notify}` : `${agent} te dejó un mensaje`);
1042
+ }
1043
+ const finals = new Map();
1044
+ for (const ev of events) {
1045
+ if (!ev || ev.direction !== "out") continue;
1046
+ if (ev.type && ev.type !== "agent") continue;
1047
+ if (ev.channel !== "telegram" && ev.channel !== "group" && ev.channel !== "a2a") continue;
1048
+ if (ev.streamed === true) continue;
1049
+ if (ev.via === "routine_delivery" || ev.via === "mobility_delivery") continue;
1050
+ const agent = (ev.author && ev.author !== "user" && ev.author !== "owner")
1051
+ ? ev.author
1052
+ : (ev.agent_slug || "agente");
1053
+ const label = ev.channel === "telegram" ? "Telegram" : ev.channel === "group" ? "Grupo" : "A2A";
1054
+ finals.set(`${ev.channel}|${agent}`, `${agent} respondió en ${label}`);
1055
+ }
1056
+ for (const text of finals.values()) pushBubble(text);
1057
+ }
1058
+
1059
+ function connect() {
1060
+ const token = readToken();
1061
+ try {
1062
+ conn = new WS(url, { headers: token ? { Authorization: `Bearer ${token}` } : {} });
1063
+ conn.on("open", () => { reconnectDelay = 1000; console.log("desktop: events feed connected"); });
1064
+ conn.on("message", (raw) => {
1065
+ let msg; try { msg = JSON.parse(raw.toString()); } catch { return; }
1066
+ handleFrame(msg);
1067
+ });
1068
+ conn.on("close", () => { conn = null; scheduleReconnect(); });
1069
+ conn.on("error", (e) => { console.warn("desktop events-feed ws error:", e.message); });
1070
+ } catch (e) {
1071
+ console.warn("desktop: events feed connect failed —", e.message);
1072
+ scheduleReconnect();
1073
+ }
1074
+ }
1075
+
1076
+ connect();
1077
+ }
1078
+
647
1079
  async function sendMessageToDaemon(text, previousMessages) {
648
1080
  const token = readToken();
649
1081
  return new Promise((resolve, reject) => {
@@ -681,11 +1113,18 @@ async function sendMessageToDaemon(text, previousMessages) {
681
1113
  // engine), retry once with `provider: "mock"` so the renderer at least gets
682
1114
  // a duration + scrubber instead of hanging. The user can plug a real TTS
683
1115
  // engine in via the Voices web admin to get audible speech.
1116
+ // The daemon's chain already tries every configured engine, so there is nothing
1117
+ // left to retry here. It used to fall back to the `mock` engine, which returns
1118
+ // a silent WAV of about the right length: the bubble grew a working-looking
1119
+ // player, the progress bar ran to the end, and no sound ever came out. A turn
1120
+ // with no voice should say so, not mime one — so a mock result is reported as
1121
+ // a failure and the bubble simply stays text.
684
1122
  function daemonTtsSay(text) {
685
1123
  return _ttsRequest(text, /* explicitProvider */ null).then((r) => {
686
- if (r.ok) return r;
687
- console.warn(`desktop: tts chain failed (${r.error}) retrying with mock`);
688
- return _ttsRequest(text, /* explicitProvider */ "mock");
1124
+ if (r.ok && r.provider === "mock") {
1125
+ return { ok: false, error: "no TTS engine answered (silent placeholder)" };
1126
+ }
1127
+ return r;
689
1128
  });
690
1129
  }
691
1130
 
@@ -721,7 +1160,12 @@ function _ttsRequest(text, explicitProvider) {
721
1160
  });
722
1161
  });
723
1162
  req.on("error", (e) => resolve({ ok: false, error: e.message }));
724
- req.setTimeout(30_000, () => { req.destroy(); resolve({ ok: false, error: "tts timeout" }); });
1163
+ // Generous on purpose. A sentence normally comes back in a second or two,
1164
+ // but the first one after the engine starts pays for loading a
1165
+ // multi-gigabyte model, and 30s was cutting that off — the reply lost its
1166
+ // voice for the one reason the user can do nothing about. Waiting is worse
1167
+ // than instant; silence is worse than waiting.
1168
+ req.setTimeout(120_000, () => { req.destroy(); resolve({ ok: false, error: "tts timeout" }); });
725
1169
  req.write(body);
726
1170
  req.end();
727
1171
  });
@@ -0,0 +1,41 @@
1
+ // AUTO-GENERATED from src/interfaces/web/src/components/agents/blobPresets.ts
2
+ // Vanilla mirror for the Electron mascot window. Keep in sync by re-running the
3
+ // generator in the desktop mascot build (see chat history / commit).
4
+ const BLOB_VIEWBOX = 256;
5
+ const BLOB_PRESETS = {
6
+ menta: { key: "menta", label: "Menta", src: "./assets/blobs/menta.png", eyeColor: "#15181C", eyes: [{ x: 121.9, y: 93.1, w: 16.0, h: 33.8, rx: 6.4 }, { x: 151.9, y: 93.1, w: 16.0, h: 33.8, rx: 6.4 }] },
7
+ parche: { key: "parche", label: "Parche", src: "./assets/blobs/parche.png", eyeColor: "#15181C", eyes: [{ x: 133.6, y: 88.6, w: 17.3, h: 33.8, rx: 6.9 }, { x: 166.1, y: 88.6, w: 17.3, h: 33.8, rx: 6.9 }] },
8
+ trino: { key: "trino", label: "Trino", src: "./assets/blobs/trino.png", eyeColor: "#15181C", eyes: [{ x: 105.5, y: 130.1, w: 18.0, h: 29.7, rx: 7.2 }, { x: 141.5, y: 130.1, w: 18.0, h: 29.7, rx: 7.2 }] },
9
+ cubi: { key: "cubi", label: "Cubi", src: "./assets/blobs/cubi.png", eyeColor: "#15181C", eyes: [{ x: 103.2, y: 93.1, w: 17.2, h: 33.8, rx: 6.9 }, { x: 135.6, y: 93.1, w: 17.2, h: 33.8, rx: 6.9 }] },
10
+ nimbo: { key: "nimbo", label: "Nimbo", src: "./assets/blobs/nimbo.png", eyeColor: "#15181C", eyes: [{ x: 103.3, y: 93.1, w: 17.1, h: 33.8, rx: 6.9 }, { x: 135.6, y: 93.1, w: 17.1, h: 33.8, rx: 6.9 }] },
11
+ papa: { key: "papa", label: "Papa", src: "./assets/blobs/papa.png", eyeColor: "#15181C", eyes: [{ x: 125.5, y: 90.9, w: 18.5, h: 30.5, rx: 7.4 }, { x: 161.6, y: 90.9, w: 18.5, h: 30.5, rx: 7.4 }] },
12
+ noche: { key: "noche", label: "Noche", src: "./assets/blobs/noche.png", eyeColor: "#3AE7B0", eyes: [{ x: 123.8, y: 133.6, w: 15.9, h: 33.8, rx: 6.4 }, { x: 157.6, y: 133.6, w: 15.9, h: 33.8, rx: 6.4 }] },
13
+ kiwi: { key: "kiwi", label: "Kiwi", src: "./assets/blobs/kiwi.png", eyeColor: "#15181C", eyes: [{ x: 123.0, y: 84.1, w: 13.1, h: 29.3, rx: 5.2 }, { x: 147.7, y: 84.1, w: 13.1, h: 29.3, rx: 5.2 }] },
14
+ gajo: { key: "gajo", label: "Gajo", src: "./assets/blobs/gajo.png", eyeColor: "#15181C", eyes: [{ x: 107.9, y: 95.3, w: 16.6, h: 29.3, rx: 6.7 }, { x: 139.3, y: 95.3, w: 16.6, h: 29.3, rx: 6.7 }] },
15
+ campana: { key: "campana", label: "Campana", src: "./assets/blobs/campana.png", eyeColor: "#15181C", eyes: [{ x: 108.6, y: 86.3, w: 15.8, h: 29.3, rx: 6.3 }, { x: 135.5, y: 86.3, w: 15.8, h: 29.3, rx: 6.3 }] },
16
+ cobalto: { key: "cobalto", label: "Cobalto", src: "./assets/blobs/cobalto.png", eyeColor: "#15181C", eyes: [{ x: 125.5, y: 95.3, w: 16.8, h: 29.3, rx: 6.7 }, { x: 157.2, y: 95.3, w: 16.8, h: 29.3, rx: 6.7 }] },
17
+ rubi: { key: "rubi", label: "Rubí", src: "./assets/blobs/rubi.png", eyeColor: "#15181C", eyes: [{ x: 123.0, y: 84.1, w: 13.1, h: 29.3, rx: 5.2 }, { x: 147.7, y: 84.1, w: 13.1, h: 29.3, rx: 5.2 }] },
18
+ trebol: { key: "trebol", label: "Trébol", src: "./assets/blobs/trebol.png", eyeColor: "#15181C", eyes: [{ x: 123.6, y: 120.1, w: 17.2, h: 29.3, rx: 6.9 }, { x: 155.1, y: 120.1, w: 17.2, h: 29.3, rx: 6.9 }] },
19
+ saturno: { key: "saturno", label: "Saturno", src: "./assets/blobs/saturno.png", eyeColor: "#15181C", eyes: [] },
20
+ onyx: { key: "onyx", label: "Onyx", src: "./assets/blobs/onyx.png", eyeColor: "#3AE7B0", eyes: [{ x: 119.7, y: 124.6, w: 16.6, h: 29.3, rx: 6.6 }, { x: 152.9, y: 124.6, w: 16.6, h: 29.3, rx: 6.6 }] },
21
+ perla: { key: "perla", label: "Perla", src: "./assets/blobs/perla.png", eyeColor: "#15181C", eyes: [{ x: 121.4, y: 108.4, w: 13.5, h: 21.4, rx: 5.4 }, { x: 148.5, y: 108.4, w: 13.5, h: 21.4, rx: 5.4 }] },
22
+ faro: { key: "faro", label: "Faro", src: "./assets/blobs/faro.png", eyeColor: "#15181C", eyes: [{ x: 94.4, y: 100.0, w: 14.2, h: 20.3, rx: 5.7 }, { x: 122.7, y: 100.0, w: 14.2, h: 20.3, rx: 5.7 }] },
23
+ brasa: { key: "brasa", label: "Brasa", src: "./assets/blobs/brasa.png", eyeColor: "#15181C", eyes: [{ x: 94.8, y: 95.2, w: 16.9, h: 18.6, rx: 6.8 }, { x: 126.3, y: 95.2, w: 16.9, h: 18.6, rx: 6.8 }] },
24
+ aqua: { key: "aqua", label: "Aqua", src: "./assets/blobs/aqua.png", eyeColor: "#15181C", eyes: [{ x: 92.9, y: 105.8, w: 10.9, h: 20.3, rx: 4.4 }, { x: 114.7, y: 105.8, w: 10.9, h: 20.3, rx: 4.4 }] },
25
+ coral: { key: "coral", label: "Coral", src: "./assets/blobs/coral.png", eyeColor: "#15181C", eyes: [{ x: 99.4, y: 147.0, w: 14.5, h: 19.1, rx: 5.8 }, { x: 129.3, y: 147.0, w: 14.5, h: 19.1, rx: 5.8 }] },
26
+ zafiro: { key: "zafiro", label: "Zafiro", src: "./assets/blobs/zafiro.png", eyeColor: "#15181C", eyes: [{ x: 105.7, y: 116.5, w: 14.3, h: 21.4, rx: 5.7 }, { x: 132.4, y: 116.5, w: 14.3, h: 21.4, rx: 5.7 }] },
27
+ pino: { key: "pino", label: "Pino", src: "./assets/blobs/pino.png", eyeColor: "#15181C", eyes: [{ x: 125.0, y: 123.2, w: 13.4, h: 20.3, rx: 5.4 }, { x: 151.9, y: 123.2, w: 13.4, h: 20.3, rx: 5.4 }] },
28
+ eclipse: { key: "eclipse", label: "Eclipse", src: "./assets/blobs/eclipse.png", eyeColor: "#060709", eyes: [{ x: 102.8, y: 111.9, w: 15.5, h: 20.3, rx: 6.2 }, { x: 131.5, y: 111.9, w: 15.5, h: 20.3, rx: 6.2 }] },
29
+ peon: { key: "peon", label: "Peón", src: "./assets/blobs/peon.png", eyeColor: "#15181C", eyes: [{ x: 109.1, y: 85.6, w: 10.2, h: 18.0, rx: 4.1 }, { x: 132.9, y: 85.6, w: 10.2, h: 18.0, rx: 4.1 }] },
30
+ ovni: { key: "ovni", label: "Ovni", src: "./assets/blobs/ovni.png", eyeColor: "#15181C", eyes: [{ x: 106.6, y: 105.0, w: 15.8, h: 16.0, rx: 6.3 }, { x: 138.1, y: 105.0, w: 15.8, h: 16.0, rx: 6.3 }] },
31
+ amatista: { key: "amatista", label: "Amatista", src: "./assets/blobs/amatista.png", eyeColor: "#15181C", eyes: [{ x: 85.8, y: 103.4, w: 16.9, h: 18.3, rx: 6.8 }, { x: 117.3, y: 103.4, w: 16.9, h: 18.3, rx: 6.8 }] },
32
+ volcan: { key: "volcan", label: "Volcán", src: "./assets/blobs/volcan.png", eyeColor: "#15181C", eyes: [{ x: 100.6, y: 97.4, w: 13.4, h: 19.1, rx: 5.4 }, { x: 127.5, y: 97.4, w: 13.4, h: 19.1, rx: 5.4 }] },
33
+ quad: { key: "quad", label: "Quad", src: "./assets/blobs/quad.png", eyeColor: "#15181C", eyes: [{ x: 80.9, y: 68.2, w: 17.6, h: 21.8, rx: 7.0 }, { x: 148.5, y: 68.2, w: 17.6, h: 21.8, rx: 7.0 }] },
34
+ cometa: { key: "cometa", label: "Cometa", src: "./assets/blobs/cometa.png", eyeColor: "#15181C", eyes: [{ x: 107.5, y: 94.8, w: 15.7, h: 21.4, rx: 6.3 }, { x: 136.9, y: 94.8, w: 15.7, h: 21.4, rx: 6.3 }] },
35
+ lila: { key: "lila", label: "Lila", src: "./assets/blobs/lila.png", eyeColor: "#15181C", eyes: [{ x: 104.8, y: 104.3, w: 14.1, h: 20.3, rx: 5.6 }, { x: 133.0, y: 104.3, w: 14.1, h: 20.3, rx: 5.6 }] },
36
+ orbita: { key: "orbita", label: "Órbita", src: "./assets/blobs/orbita.png", eyeColor: "#060709", eyes: [{ x: 104.3, y: 96.7, w: 15.8, h: 18.7, rx: 6.3 }, { x: 135.9, y: 96.7, w: 15.8, h: 18.7, rx: 6.3 }] },
37
+ caracol: { key: "caracol", label: "Caracol", src: "./assets/blobs/caracol.png", eyeColor: "#15181C", eyes: [{ x: 149.9, y: 109.4, w: 14.6, h: 17.1, rx: 5.9 }, { x: 181.4, y: 109.4, w: 14.6, h: 17.1, rx: 5.9 }] },
38
+ iris: { key: "iris", label: "Iris", src: "./assets/blobs/iris.png", eyeColor: "#15181C", eyes: [{ x: 97.7, y: 106.6, w: 13.7, h: 20.3, rx: 5.5 }, { x: 125.1, y: 106.6, w: 13.7, h: 20.3, rx: 5.5 }] },
39
+ laguna: { key: "laguna", label: "Laguna", src: "./assets/blobs/laguna.png", eyeColor: "#15181C", eyes: [{ x: 106.6, y: 83.8, w: 15.8, h: 18.5, rx: 6.3 }, { x: 138.1, y: 83.8, w: 15.8, h: 18.5, rx: 6.3 }] },
40
+ carbon: { key: "carbon", label: "Carbón", src: "./assets/blobs/carbon.png", eyeColor: "#060709", eyes: [{ x: 93.7, y: 99.3, w: 16.3, h: 21.4, rx: 6.5 }, { x: 124.2, y: 99.3, w: 16.3, h: 21.4, rx: 6.5 }] },
41
+ };